From 17174016ec6603afe87a65282f9b7eb55f2eafeb Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sun, 17 Aug 2014 21:53:34 +0200 Subject: Remove all trailing whitespaces. --- README.rst | 8 +- docs/_static/nature.css | 68 ++-- docs/_static/sphinxdoc.css | 2 +- docs/api/exceptions.rst | 2 +- docs/api/xmlstream/stanzabase.rst | 2 +- docs/architecture.rst | 10 +- docs/create_plugin.rst | 8 +- docs/event_index.rst | 38 +-- docs/getting_started/component.rst | 6 +- docs/getting_started/echobot.rst | 22 +- docs/getting_started/iq.rst | 8 +- docs/getting_started/proxy.rst | 2 +- docs/getting_started/sendlogout.rst | 8 +- docs/guide_xep_0030.rst | 4 +- docs/index.rst | 12 +- docs/license.rst | 2 +- docs/xeps.rst | 6 +- docs/xmpp_tdg.rst | 8 +- examples/custom_stanzas/custom_stanza_user.py | 2 +- examples/custom_stanzas/stanza.py | 8 +- examples/thirdparty_auth.py | 10 +- examples/user_location.py | 2 +- slixmpp/plugins/xep_0009/rpc.py | 436 +++++++++++++------------- slixmpp/plugins/xep_0012/last_activity.py | 312 +++++++++--------- slixmpp/plugins/xep_0045.py | 2 +- slixmpp/plugins/xep_0065/proxy.py | 2 +- slixmpp/plugins/xep_0086/legacy_error.py | 92 +++--- slixmpp/plugins/xep_0153/vcard_avatar.py | 2 +- slixmpp/plugins/xep_0202/time.py | 196 ++++++------ slixmpp/plugins/xep_0323/device.py | 48 +-- slixmpp/plugins/xep_0323/sensordata.py | 128 ++++---- slixmpp/plugins/xep_0323/stanza/sensordata.py | 72 ++--- slixmpp/plugins/xep_0325/control.py | 126 ++++---- slixmpp/plugins/xep_0325/device.py | 24 +- slixmpp/plugins/xep_0325/stanza/control.py | 82 ++--- slixmpp/xmlstream/resolver.py | 4 +- tests/test_plugins.py | 2 +- tests/test_stanza_xep_0323.py | 42 +-- tests/test_stanza_xep_0325.py | 6 +- tests/test_stream_xep_0323.py | 182 +++++------ tests/test_stream_xep_0325.py | 28 +- 41 files changed, 1012 insertions(+), 1012 deletions(-) diff --git a/README.rst b/README.rst index e2c82258..1904f8e7 100644 --- a/README.rst +++ b/README.rst @@ -80,7 +80,7 @@ Slixmpp projects:: if __name__ == '__main__': - # Ideally use optparse or argparse to get JID, + # Ideally use optparse or argparse to get JID, # password, and log level. logging.basicConfig(level=logging.DEBUG, @@ -101,15 +101,15 @@ Credits ------- **Main Author:** Nathan Fritz - `fritzy@netflint.net `_, + `fritzy@netflint.net `_, `@fritzy `_ Nathan is also the author of XMPPHP and `Seesmic-AS3-XMPP - `_, and a former member of + `_, and a former member of the XMPP Council. **Co-Author:** Lance Stout - `lancestout@gmail.com `_, + `lancestout@gmail.com `_, `@lancestout `_ **Contributors:** diff --git a/docs/_static/nature.css b/docs/_static/nature.css index 52b328ea..b271ec97 100644 --- a/docs/_static/nature.css +++ b/docs/_static/nature.css @@ -8,11 +8,11 @@ * :license: BSD, see LICENSE for details. * */ - + @import url("basic.css"); - + /* -- page layout ----------------------------------------------------------- */ - + body { font-family: Arial, sans-serif; font-size: 100%; @@ -34,18 +34,18 @@ div.bodywrapper { hr { border: 1px solid #B1B4B6; } - + div.document { background-color: #eee; } - + div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 30px 30px; font-size: 0.9em; } - + div.footer { color: #555; width: 100%; @@ -53,12 +53,12 @@ div.footer { text-align: center; font-size: 75%; } - + div.footer a { color: #444; text-decoration: underline; } - + div.related { background-color: #6BA81E; line-height: 32px; @@ -66,11 +66,11 @@ div.related { text-shadow: 0px 1px 0 #444; font-size: 0.9em; } - + div.related a { color: #E2F3CC; } - + div.sphinxsidebar { font-size: 0.75em; line-height: 1.5em; @@ -79,7 +79,7 @@ div.sphinxsidebar { div.sphinxsidebarwrapper{ padding: 20px 0; } - + div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: Arial, sans-serif; @@ -95,30 +95,30 @@ div.sphinxsidebar h4 { div.sphinxsidebar h4{ font-size: 1.1em; } - + div.sphinxsidebar h3 a { color: #444; } - - + + div.sphinxsidebar p { color: #888; padding: 5px 20px; } - + div.sphinxsidebar p.topless { } - + div.sphinxsidebar ul { margin: 10px 20px; padding: 0; color: #000; } - + div.sphinxsidebar a { color: #444; } - + div.sphinxsidebar input { border: 1px solid #ccc; font-family: sans-serif; @@ -128,19 +128,19 @@ div.sphinxsidebar input { div.sphinxsidebar input[type=text]{ margin-left: 20px; } - + /* -- body styles ----------------------------------------------------------- */ - + a { color: #005B81; text-decoration: none; } - + a:hover { color: #E32E00; text-decoration: underline; } - + div.body h1, div.body h2, div.body h3, @@ -155,30 +155,30 @@ div.body h6 { padding: 5px 0 5px 10px; text-shadow: 0px 1px 0 white } - + div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } div.body h2 { font-size: 150%; background-color: #C8D5E3; } div.body h3 { font-size: 120%; background-color: #D8DEE3; } div.body h4 { font-size: 110%; background-color: #D8DEE3; } div.body h5 { font-size: 100%; background-color: #D8DEE3; } div.body h6 { font-size: 100%; background-color: #D8DEE3; } - + a.headerlink { color: #c60f0f; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; } - + a.headerlink:hover { background-color: #c60f0f; color: white; } - + div.body p, div.body dd, div.body li { line-height: 1.5em; } - + div.admonition p.admonition-title + p { display: inline; } @@ -191,29 +191,29 @@ div.note { background-color: #eee; border: 1px solid #ccc; } - + div.seealso { background-color: #ffc; border: 1px solid #ff6; } - + div.topic { background-color: #eee; } - + div.warning { background-color: #ffe4e4; border: 1px solid #f66; } - + p.admonition-title { display: inline; } - + p.admonition-title:after { content: ":"; } - + pre { padding: 10px; background-color: White; @@ -225,7 +225,7 @@ pre { -webkit-box-shadow: 1px 1px 1px #d8d8d8; -moz-box-shadow: 1px 1px 1px #d8d8d8; } - + tt { background-color: #ecf0f3; color: #222; diff --git a/docs/_static/sphinxdoc.css b/docs/_static/sphinxdoc.css index 0a428074..55c574f6 100644 --- a/docs/_static/sphinxdoc.css +++ b/docs/_static/sphinxdoc.css @@ -134,7 +134,7 @@ div.footer a { /* -- body styles ----------------------------------------------------------- */ -p { +p { margin: 0.8em 0 0.5em 0; } diff --git a/docs/api/exceptions.rst b/docs/api/exceptions.rst index 0736a09c..51e2e170 100644 --- a/docs/api/exceptions.rst +++ b/docs/api/exceptions.rst @@ -3,7 +3,7 @@ Exceptions .. module:: slixmpp.exceptions - + .. autoexception:: XMPPError :members: diff --git a/docs/api/xmlstream/stanzabase.rst b/docs/api/xmlstream/stanzabase.rst index ec28bafe..216ceebe 100644 --- a/docs/api/xmlstream/stanzabase.rst +++ b/docs/api/xmlstream/stanzabase.rst @@ -101,7 +101,7 @@ of an interface defined by the parent. - :ref:`create-stanza-plugins` - :ref:`create-extension-plugins` - :ref:`override-parent-interfaces` - + Registering Stanza Plugins -------------------------- diff --git a/docs/architecture.rst b/docs/architecture.rst index 2d0170d2..cfc56f3e 100644 --- a/docs/architecture.rst +++ b/docs/architecture.rst @@ -88,7 +88,7 @@ when this bit of XML is received (with an assumed namespace of callback, the callback function is executed with the stanza as its only parameter. - .. warning:: + .. warning:: The callback, aka :term:`stream handler`, is executed in the main event processing thread. If the handler blocks, event processing will also block. @@ -117,7 +117,7 @@ when this bit of XML is received (with an assumed namespace of paired with an :term:`event handler`:: ('event', 'message', msg_copy1, custom_event_handler_1) - ('event', 'message', msg_copy2, custom_evetn_handler_2) + ('event', 'message', msg_copy2, custom_evetn_handler_2) 5. **Process Custom Events** @@ -127,9 +127,9 @@ when this bit of XML is received (with an assumed namespace of will be spawned for it. .. note:: - Events may be raised without needing :term:`stanza objects `. - For example, you could use ``self.event('custom', {'a': 'b'})``. - You don't even need any arguments: ``self.event('no_parameters')``. + Events may be raised without needing :term:`stanza objects `. + For example, you could use ``self.event('custom', {'a': 'b'})``. + You don't even need any arguments: ``self.event('no_parameters')``. However, every event handler MUST accept at least one argument. Finally, after a long trek, our message is handed off to the user's diff --git a/docs/create_plugin.rst b/docs/create_plugin.rst index 7e082a7e..98d682eb 100644 --- a/docs/create_plugin.rst +++ b/docs/create_plugin.rst @@ -40,7 +40,7 @@ module. To do so, use the following form when registering the plugin: self.register_plugin('myplugin', module=mod_containing_my_plugin) The plugin name must be the same as the plugin's class name. - + Now, we can open our favorite text editors and create ``xep_0077.py`` in ``Slixmpp/slixmpp/plugins``. We want to do some basic house-keeping and declare the name and description of the XEP we are implementing. If you @@ -535,9 +535,9 @@ with some additional registration fields implemented. namespace = 'jabber:iq:register' name = 'query' plugin_attrib = 'register' - interfaces = set(('username', 'password', 'email', 'nick', 'name', - 'first', 'last', 'address', 'city', 'state', 'zip', - 'phone', 'url', 'date', 'misc', 'text', 'key', + interfaces = set(('username', 'password', 'email', 'nick', 'name', + 'first', 'last', 'address', 'city', 'state', 'zip', + 'phone', 'url', 'date', 'misc', 'text', 'key', 'registered', 'remove', 'instructions')) sub_interfaces = interfaces diff --git a/docs/event_index.rst b/docs/event_index.rst index b5f249f2..3dd45ce8 100644 --- a/docs/event_index.rst +++ b/docs/event_index.rst @@ -60,13 +60,13 @@ Event Index disco_info - **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoInfo` - **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030` - + Triggered whenever a ``disco#info`` result stanza is received. disco_items - **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoItems` - **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030` - + Triggered whenever a ``disco#items`` result stanza is received. disconnected @@ -88,13 +88,13 @@ Event Index gmail_notify - **Data:** ``{}`` - **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify` - + Signal that there are unread emails for the Gmail account associated with the current XMPP account. gmail_messages - **Data:** :py:class:`~slixmpp.Iq` - **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify` - + Signal that there are unread emails for the Gmail account associated with the current XMPP account. got_online @@ -122,19 +122,19 @@ Event Index groupchat_message - **Data:** :py:class:`~slixmpp.Message` - **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045` - + Triggered whenever a message is received from a multi-user chat room. groupchat_presence - **Data:** :py:class:`~slixmpp.Presence` - **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045` - + Triggered whenever a presence stanza is received from a user in a multi-user chat room. groupchat_subject - **Data:** :py:class:`~slixmpp.Message` - **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045` - + Triggered whenever the subject of a multi-user chat room is changed, or announced when joining a room. killed @@ -148,7 +148,7 @@ Event Index message - **Data:** :py:class:`~slixmpp.Message` - **Source:** :py:class:`BaseXMPP ` - + Makes the contents of message stanzas available whenever one is received. Be sure to check the message type in order to handle error messages. @@ -183,67 +183,67 @@ Event Index presence_available - **Data:** :py:class:`~slixmpp.Presence` - **Source:** :py:class:`~slixmpp.BaseXMPP` - + A presence stanza with a type of '``available``' is received. presence_error - **Data:** :py:class:`~slixmpp.Presence` - **Source:** :py:class:`~slixmpp.BaseXMPP` - + A presence stanza with a type of '``error``' is received. presence_form - **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form` - **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004` - + This event is present in the XEP-0004 plugin code, but is currently not used. presence_probe - **Data:** :py:class:`~slixmpp.Presence` - **Source:** :py:class:`~slixmpp.BaseXMPP` - + A presence stanza with a type of '``probe``' is received. presence_subscribe - **Data:** :py:class:`~slixmpp.Presence` - **Source:** :py:class:`~slixmpp.BaseXMPP` - + A presence stanza with a type of '``subscribe``' is received. presence_subscribed - **Data:** :py:class:`~slixmpp.Presence` - **Source:** :py:class:`~slixmpp.BaseXMPP` - + A presence stanza with a type of '``subscribed``' is received. presence_unavailable - **Data:** :py:class:`~slixmpp.Presence` - **Source:** :py:class:`~slixmpp.BaseXMPP` - + A presence stanza with a type of '``unavailable``' is received. presence_unsubscribe - **Data:** :py:class:`~slixmpp.Presence` - **Source:** :py:class:`~slixmpp.BaseXMPP` - + A presence stanza with a type of '``unsubscribe``' is received. presence_unsubscribed - **Data:** :py:class:`~slixmpp.Presence` - **Source:** :py:class:`~slixmpp.BaseXMPP` - + A presence stanza with a type of '``unsubscribed``' is received. roster_update - **Data:** :py:class:`~slixmpp.stanza.Roster` - **Source:** :py:class:`~slixmpp.ClientXMPP` - + An IQ result containing roster entries is received. sent_presence - **Data:** ``{}`` - **Source:** :py:class:`~slixmpp.roster.multi.Roster` - + Signal that an initial presence stanza has been written to the XML stream. session_end diff --git a/docs/getting_started/component.rst b/docs/getting_started/component.rst index efac7ad3..484a8e84 100644 --- a/docs/getting_started/component.rst +++ b/docs/getting_started/component.rst @@ -5,7 +5,7 @@ Create and Run a Server Component ================================= .. note:: - + If you have any issues working through this quickstart guide or the other tutorials here, please either send a message to the `mailing list `_ @@ -21,8 +21,8 @@ or ``easy_install``. pip install slixmpp # Or: easy_install slixmpp -Many XMPP applications eventually graduate to requiring to run as a server -component in order to meet scalability requirements. To demonstrate how to +Many XMPP applications eventually graduate to requiring to run as a server +component in order to meet scalability requirements. To demonstrate how to turn an XMPP client bot into a component, we'll turn the echobot example (:ref:`echobot`) into a component version. diff --git a/docs/getting_started/echobot.rst b/docs/getting_started/echobot.rst index df5aa2b0..0d0bab72 100644 --- a/docs/getting_started/echobot.rst +++ b/docs/getting_started/echobot.rst @@ -5,7 +5,7 @@ Slixmpp Quickstart - Echo Bot =============================== .. note:: - + If you have any issues working through this quickstart guide or the other tutorials here, please either send a message to the `mailing list `_ @@ -93,7 +93,7 @@ as well. .. code-block:: python class EchoBot(slixmpp.ClientXMPP): - + def __init__(self, jid, password): super(EchoBot, self).__init__(jid, password) @@ -102,7 +102,7 @@ Handling Session Start The XMPP spec requires clients to broadcast its presence and retrieve its roster (buddy list) once it connects and establishes a session with the XMPP server. Until these two tasks are completed, some servers may not deliver or send messages or presence notifications to the client. So we now -need to be sure that we retrieve our roster and send an initial presence once the session has +need to be sure that we retrieve our roster and send an initial presence once the session has started. To do that, we will register an event handler for the :term:`session_start` event. .. code-block:: python @@ -198,7 +198,7 @@ or ``chat``. (Other potential types are ``error``, ``headline``, and ``groupchat Let's take a closer look at the ``.reply()`` method used above. For message stanzas, ``.reply()`` accepts the parameter ``body`` (also as the first positional argument), -which is then used as the value of the ```` element of the message. +which is then used as the value of the ```` element of the message. Setting the appropriate ``to`` JID is also handled by ``.reply()``. Another way to have sent the reply message would be to use :meth:`send_message `, @@ -242,7 +242,7 @@ the newer ``argparse`` module. We want to accept three parameters: the JID for the echo bot, its password, and a flag for displaying the debugging logs. We also want these to be optional parameters, since passing -a password directly through the command line can be a security risk. +a password directly through the command line can be a security risk. .. code-block:: python @@ -303,21 +303,21 @@ the ``EchoBot.__init__`` method instead. .. note:: - If you are using the OpenFire server, you will need to include an additional + If you are using the OpenFire server, you will need to include an additional configuration step. OpenFire supports a different version of SSL than what most servers and Slixmpp support. .. code-block:: python - + import ssl xmpp.ssl_version = ssl.PROTOCOL_SSLv3 Now we're ready to connect and begin echoing messages. If you have the package ``dnspython`` installed, then the :meth:`slixmpp.clientxmpp.ClientXMPP` method will perform a DNS query to find the appropriate server to connect to for the -given JID. If you do not have ``dnspython``, then Slixmpp will attempt to +given JID. If you do not have ``dnspython``, then Slixmpp will attempt to connect to the hostname used by the JID, unless an address tuple is supplied -to :meth:`slixmpp.clientxmpp.ClientXMPP`. +to :meth:`slixmpp.clientxmpp.ClientXMPP`. .. code-block:: python @@ -349,12 +349,12 @@ to :meth:`slixmpp.clientxmpp.ClientXMPP`. To begin responding to messages, you'll see we called :meth:`slixmpp.basexmpp.BaseXMPP.process` which will start the event handling, send queue, and XML reader threads. It will also call the :meth:`slixmpp.plugins.base.base_plugin.post_init` method on all registered plugins. By -passing ``block=True`` to :meth:`slixmpp.basexmpp.BaseXMPP.process` we are running the +passing ``block=True`` to :meth:`slixmpp.basexmpp.BaseXMPP.process` we are running the main processing loop in the main thread of execution. The :meth:`slixmpp.basexmpp.BaseXMPP.process` call will not return until after Slixmpp disconnects. If you need to run the client in the background for another program, use ``block=False`` to spawn the processing loop in its own thread. -.. note:: +.. note:: Before 1.0, controlling the blocking behaviour of :meth:`slixmpp.basexmpp.BaseXMPP.process` was done via the ``threaded`` argument. This arrangement was a source of confusion because some users diff --git a/docs/getting_started/iq.rst b/docs/getting_started/iq.rst index cbf3d476..be15e170 100644 --- a/docs/getting_started/iq.rst +++ b/docs/getting_started/iq.rst @@ -36,7 +36,7 @@ stanzas this way. The relevant methods are: * :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_error` * :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_query` -These methods all follow the same pattern: create or modify an existing +These methods all follow the same pattern: create or modify an existing :class:`~slixmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based on the method name, and finally add a ```` element with the given namespace. For example, to produce the query above, you would use: @@ -74,7 +74,7 @@ These options are: To change the timeout for a single call, the ``timeout`` parameter works: .. code-block:: python - + iq.send(timeout=60) * ``callback``: When not using a blocking call, using the ``callback`` @@ -85,7 +85,7 @@ These options are: .. code-block:: python - cb_name = iq.send(callback=self.a_callback) + cb_name = iq.send(callback=self.a_callback) # ... later if we need to cancel self.remove_handler(cb_name) @@ -133,7 +133,7 @@ interfacting with the :class:`~slixmpp.stanza.iq.Iq` payload. * :ref:`create-plugin` * :ref:`work-with-stanzas` * :ref:`using-handlers-matchers` - + The typical way to respond to :class:`~slixmpp.stanza.iq.Iq` requests is to register stream handlers. As an example, suppose we create a stanza class diff --git a/docs/getting_started/proxy.rst b/docs/getting_started/proxy.rst index b5e74180..e45b2b3a 100644 --- a/docs/getting_started/proxy.rst +++ b/docs/getting_started/proxy.rst @@ -5,7 +5,7 @@ Enable HTTP Proxy Support ========================= .. note:: - + If you have any issues working through this quickstart guide or the other tutorials here, please either send a message to the `mailing list `_ diff --git a/docs/getting_started/sendlogout.rst b/docs/getting_started/sendlogout.rst index 5b23a469..7669e340 100644 --- a/docs/getting_started/sendlogout.rst +++ b/docs/getting_started/sendlogout.rst @@ -2,7 +2,7 @@ Sign in, Send a Message, and Disconnect ======================================= .. note:: - + If you have any issues working through this quickstart guide or the other tutorials here, please either send a message to the `mailing list `_ @@ -10,7 +10,7 @@ Sign in, Send a Message, and Disconnect `_. A common use case for Slixmpp is to send one-off messages from -time to time. For example, one use case could be sending out a notice when +time to time. For example, one use case could be sending out a notice when a shell script finishes a task. We will create our one-shot bot based on the pattern explained in :ref:`echobot`. To @@ -24,7 +24,7 @@ for the JID that will receive our message, and the string content of the message class SendMsgBot(slixmpp.ClientXMPP): - + def __init__(self, jid, password, recipient, msg): super(SendMsgBot, self).__init__(jid, password) @@ -52,7 +52,7 @@ Finally, we need to disconnect the client using :meth:`disconnect ` without any parameters, then it is possible for the client to disconnect before the send queue is processed and the message is actually -sent on the wire. To ensure that our message is processed, we use +sent on the wire. To ensure that our message is processed, we use :meth:`disconnect(wait=True) `. .. code-block:: python diff --git a/docs/guide_xep_0030.rst b/docs/guide_xep_0030.rst index cd0f4850..674b9eb5 100644 --- a/docs/guide_xep_0030.rst +++ b/docs/guide_xep_0030.rst @@ -159,7 +159,7 @@ item itself, and the JID and node that will own the item. .. note:: In this case, the owning JID and node are provided with the - parameters ``ijid`` and ``node``. + parameters ``ijid`` and ``node``. Peforming Disco Queries ----------------------- @@ -197,5 +197,5 @@ a full Iq stanza. info = self['xep_0030'].get_info(node='foo', local=True) items = self['xep_0030'].get_items(jid='somejid@mycomponent.example.com', - node='bar', + node='bar', local=True) diff --git a/docs/index.rst b/docs/index.rst index 33d6cd00..3e97fb09 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -31,7 +31,7 @@ Slixmpp Slixmpp is an :ref:`MIT licensed ` XMPP library for Python 2.6/3.1+, and is featured in examples in -`XMPP: The Definitive Guide `_ +`XMPP: The Definitive Guide `_ by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived here from reading the Definitive Guide, please see the notes on updating the examples to the latest version of Slixmpp. @@ -113,7 +113,7 @@ Here's your first Slixmpp Bot: if __name__ == '__main__': - # Ideally use optparse or argparse to get JID, + # Ideally use optparse or argparse to get JID, # password, and log level. logging.basicConfig(level=logging.DEBUG, @@ -129,7 +129,7 @@ Getting Started (with Examples) ------------------------------- .. toctree:: :maxdepth: 1 - + getting_started/echobot getting_started/sendlogout getting_started/component @@ -144,7 +144,7 @@ Tutorials, FAQs, and How To Guides ---------------------------------- .. toctree:: :maxdepth: 1 - + faq xeps xmpp_tdg @@ -156,7 +156,7 @@ Tutorials, FAQs, and How To Guides Plugin Guides ~~~~~~~~~~~~~ -.. toctree:: +.. toctree:: :maxdepth: 1 guide_xep_0030 @@ -173,7 +173,7 @@ API Reference ------------- .. toctree:: :maxdepth: 2 - + event_index api/clientxmpp api/componentxmpp diff --git a/docs/license.rst b/docs/license.rst index cbcf5c11..d9505344 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -1,4 +1,4 @@ -.. _license: +.. _license: License (MIT) ============= diff --git a/docs/xeps.rst b/docs/xeps.rst index 3653d10a..c5b4592d 100644 --- a/docs/xeps.rst +++ b/docs/xeps.rst @@ -4,9 +4,9 @@ Supported XEPS ======= ============================= ================ XEP Description Notes ======= ============================= ================ -`0004`_ Data forms -`0009`_ Jabber RPC -`0012`_ Last Activity +`0004`_ Data forms +`0009`_ Jabber RPC +`0012`_ Last Activity `0030`_ Service Discovery `0033`_ Extended Stanza Addressing `0045`_ Multi-User Chat (MUC) Client-side only diff --git a/docs/xmpp_tdg.rst b/docs/xmpp_tdg.rst index c0d85196..dc921f8f 100644 --- a/docs/xmpp_tdg.rst +++ b/docs/xmpp_tdg.rst @@ -1,7 +1,7 @@ Following *XMPP: The Definitive Guide* ====================================== -Slixmpp was featured in the first edition of the O'Reilly book +Slixmpp was featured in the first edition of the O'Reilly book `XMPP: The Definitive Guide `_ by Peter Saint-Andre, Kevin Smith, and Remko Tronçon. The original source code for the book's examples can be found at http://github.com/remko/xmpp-tdg. An @@ -79,7 +79,7 @@ Updated Code user = self.backend.getUserFromJID(event["from"].jid) if user is not None: self.backend.addMessageFromUser(message, user) - + def handleMessageAddedToBackend(self, message) : body = message.user + ": " + message.text htmlBody = "

%(user)s: %(message)s

" % { @@ -203,7 +203,7 @@ Example 14-7. (Page 225) **Extended CheshiR IM server component implementation.** .. note:: - Since the CheshiR examples build on each other, see previous + Since the CheshiR examples build on each other, see previous sections for corrections to code that is not marked as new in the book example. @@ -246,4 +246,4 @@ Updated Code self.sendAllContactSubscriptionRequestsToUser(userJID) `View full source `_ | -`View original code `_ +`View original code `_ diff --git a/examples/custom_stanzas/custom_stanza_user.py b/examples/custom_stanzas/custom_stanza_user.py index 4e8337f2..66bad523 100755 --- a/examples/custom_stanzas/custom_stanza_user.py +++ b/examples/custom_stanzas/custom_stanza_user.py @@ -82,7 +82,7 @@ class ActionUserBot(slixmpp.ClientXMPP): iq2['type'] = 'set' iq2['action']['method'] = 'bye' iq2.send(block=False) - + # The wait=True delays the disconnect until the queue # of stanzas to be sent becomes empty. self.disconnect(wait=True) diff --git a/examples/custom_stanzas/stanza.py b/examples/custom_stanzas/stanza.py index ba109b06..b2c6f766 100644 --- a/examples/custom_stanzas/stanza.py +++ b/examples/custom_stanzas/stanza.py @@ -11,7 +11,7 @@ class Action(ElementBase): X """ - + #: The `name` field refers to the basic XML tag name of the #: stanza. Here, the tag name will be 'action'. name = 'action' @@ -22,9 +22,9 @@ class Action(ElementBase): #: The `plugin_attrib` value is the name that can be used #: with a parent stanza to access this stanza. For example #: from an Iq stanza object, accessing: - #: + #: #: iq['action'] - #: + #: #: would reference an Action object, and will even create #: an Action object and append it to the Iq stanza if #: one doesn't already exist. @@ -49,7 +49,7 @@ class Action(ElementBase): #: the sub_interfaces set. For example, here all interfaces #: are marked as sub_interfaces, and so the XML produced will #: look like: - #: + #: #: #: foo #: diff --git a/examples/thirdparty_auth.py b/examples/thirdparty_auth.py index 9318854b..4129fa91 100755 --- a/examples/thirdparty_auth.py +++ b/examples/thirdparty_auth.py @@ -121,7 +121,7 @@ if __name__ == '__main__': if args.password is None: args.password = getpass("Password: ") - + access_token = None # Since documentation on how to work with Google tokens @@ -147,7 +147,7 @@ if __name__ == '__main__': 'Passwd': args.password }) headers = { - 'Content-Type': 'application/x-www-form-urlencoded' + 'Content-Type': 'application/x-www-form-urlencoded' } try: conn.request('POST', '/accounts/ClientLogin', params, headers) @@ -195,12 +195,12 @@ if __name__ == '__main__': # We're using an access token instead of a password, so we'll use `''` as # a password argument filler. - xmpp = ThirdPartyAuthBot(args.jid, '') + xmpp = ThirdPartyAuthBot(args.jid, '') xmpp.credentials['access_token'] = access_token # The credentials dictionary is used to provide additional authentication # information beyond just a password. - + xmpp.register_plugin('xep_0030') # Service Discovery xmpp.register_plugin('xep_0004') # Data Forms xmpp.register_plugin('xep_0060') # PubSub @@ -218,7 +218,7 @@ if __name__ == '__main__': # xmpp.ca_certs = "path/to/ca/cert" # Connect to the XMPP server and start processing XMPP stanzas. - # Google only allows one SASL attempt per connection, so in order to + # Google only allows one SASL attempt per connection, so in order to # enable the X-GOOGLE-TOKEN mechanism, we'll disable TLS. xmpp.connect() xmpp.process() diff --git a/examples/user_location.py b/examples/user_location.py index 8840ec85..5a30f7af 100755 --- a/examples/user_location.py +++ b/examples/user_location.py @@ -25,7 +25,7 @@ class LocationBot(ClientXMPP): super(LocationBot, self).__init__(jid, password) self.add_event_handler('session_start', self.start) - self.add_event_handler('user_location_publish', + self.add_event_handler('user_location_publish', self.user_location_publish) self.register_plugin('xep_0004') diff --git a/slixmpp/plugins/xep_0009/rpc.py b/slixmpp/plugins/xep_0009/rpc.py index ff17c417..674d13d6 100644 --- a/slixmpp/plugins/xep_0009/rpc.py +++ b/slixmpp/plugins/xep_0009/rpc.py @@ -1,218 +1,218 @@ -""" - Slixmpp: The Slick XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON). - This file is part of Slixmpp. - - See the file LICENSE for copying permission. -""" - -import logging - -from slixmpp import Iq -from slixmpp.xmlstream import ET, register_stanza_plugin -from slixmpp.xmlstream.handler import Callback -from slixmpp.xmlstream.matcher import MatchXPath -from slixmpp.plugins import BasePlugin -from slixmpp.plugins.xep_0009 import stanza -from slixmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse - - -log = logging.getLogger(__name__) - - -class XEP_0009(BasePlugin): - - name = 'xep_0009' - description = 'XEP-0009: Jabber-RPC' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Iq, RPCQuery) - register_stanza_plugin(RPCQuery, MethodCall) - register_stanza_plugin(RPCQuery, MethodResponse) - - self.xmpp.register_handler( - Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)), - self._handle_method_call) - ) - self.xmpp.register_handler( - Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)), - self._handle_method_response) - ) - self.xmpp.register_handler( - Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)), - self._handle_error) - ) - self.xmpp.add_event_handler('jabber_rpc_method_call', self._on_jabber_rpc_method_call) - self.xmpp.add_event_handler('jabber_rpc_method_response', self._on_jabber_rpc_method_response) - self.xmpp.add_event_handler('jabber_rpc_method_fault', self._on_jabber_rpc_method_fault) - self.xmpp.add_event_handler('jabber_rpc_error', self._on_jabber_rpc_error) - self.xmpp.add_event_handler('error', self._handle_error) - #self.activeCalls = [] - - self.xmpp['xep_0030'].add_feature('jabber:iq:rpc') - self.xmpp['xep_0030'].add_identity('automation','rpc') - - def make_iq_method_call(self, pto, pmethod, params): - iq = self.xmpp.makeIqSet() - iq.attrib['to'] = pto - iq.attrib['from'] = self.xmpp.boundjid.full - iq.enable('rpc_query') - iq['rpc_query']['method_call']['method_name'] = pmethod - iq['rpc_query']['method_call']['params'] = params - return iq; - - def make_iq_method_response(self, pid, pto, params): - iq = self.xmpp.makeIqResult(pid) - iq.attrib['to'] = pto - iq.attrib['from'] = self.xmpp.boundjid.full - iq.enable('rpc_query') - iq['rpc_query']['method_response']['params'] = params - return iq - - def make_iq_method_response_fault(self, pid, pto, params): - iq = self.xmpp.makeIqResult(pid) - iq.attrib['to'] = pto - iq.attrib['from'] = self.xmpp.boundjid.full - iq.enable('rpc_query') - iq['rpc_query']['method_response']['params'] = None - iq['rpc_query']['method_response']['fault'] = params - return iq - -# def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition): -# iq = self.xmpp.makeIqError(pid) -# iq.attrib['to'] = pto -# iq.attrib['from'] = self.xmpp.boundjid.full -# iq['error']['code'] = code -# iq['error']['type'] = type -# iq['error']['condition'] = condition -# iq['rpc_query']['method_call']['method_name'] = pmethod -# iq['rpc_query']['method_call']['params'] = params -# return iq - - def _item_not_found(self, iq): - payload = iq.get_payload() - iq.reply().error().set_payload(payload); - iq['error']['code'] = '404' - iq['error']['type'] = 'cancel' - iq['error']['condition'] = 'item-not-found' - return iq - - def _undefined_condition(self, iq): - payload = iq.get_payload() - iq.reply().error().set_payload(payload) - iq['error']['code'] = '500' - iq['error']['type'] = 'cancel' - iq['error']['condition'] = 'undefined-condition' - return iq - - def _forbidden(self, iq): - payload = iq.get_payload() - iq.reply().error().set_payload(payload) - iq['error']['code'] = '403' - iq['error']['type'] = 'auth' - iq['error']['condition'] = 'forbidden' - return iq - - def _recipient_unvailable(self, iq): - payload = iq.get_payload() - iq.reply().error().set_payload(payload) - iq['error']['code'] = '404' - iq['error']['type'] = 'wait' - iq['error']['condition'] = 'recipient-unavailable' - return iq - - def _handle_method_call(self, iq): - type = iq['type'] - if type == 'set': - log.debug("Incoming Jabber-RPC call from %s", iq['from']) - self.xmpp.event('jabber_rpc_method_call', iq) - else: - if type == 'error' and ['rpc_query'] is None: - self.handle_error(iq) - else: - log.debug("Incoming Jabber-RPC error from %s", iq['from']) - self.xmpp.event('jabber_rpc_error', iq) - - def _handle_method_response(self, iq): - if iq['rpc_query']['method_response']['fault'] is not None: - log.debug("Incoming Jabber-RPC fault from %s", iq['from']) - #self._on_jabber_rpc_method_fault(iq) - self.xmpp.event('jabber_rpc_method_fault', iq) - else: - log.debug("Incoming Jabber-RPC response from %s", iq['from']) - self.xmpp.event('jabber_rpc_method_response', iq) - - def _handle_error(self, iq): - print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq) - print("#######################") - print("### NOT IMPLEMENTED ###") - print("#######################") - - def _on_jabber_rpc_method_call(self, iq, forwarded=False): - """ - A default handler for Jabber-RPC method call. If another - handler is registered, this one will defer and not run. - - If this handler is called by your own custom handler with - forwarded set to True, then it will run as normal. - """ - if not forwarded and self.xmpp.event_handled('jabber_rpc_method_call') > 1: - return - # Reply with error by default - error = self.client.plugin['xep_0009']._item_not_found(iq) - error.send() - - def _on_jabber_rpc_method_response(self, iq, forwarded=False): - """ - A default handler for Jabber-RPC method response. If another - handler is registered, this one will defer and not run. - - If this handler is called by your own custom handler with - forwarded set to True, then it will run as normal. - """ - if not forwarded and self.xmpp.event_handled('jabber_rpc_method_response') > 1: - return - error = self.client.plugin['xep_0009']._recpient_unavailable(iq) - error.send() - - def _on_jabber_rpc_method_fault(self, iq, forwarded=False): - """ - A default handler for Jabber-RPC fault response. If another - handler is registered, this one will defer and not run. - - If this handler is called by your own custom handler with - forwarded set to True, then it will run as normal. - """ - if not forwarded and self.xmpp.event_handled('jabber_rpc_method_fault') > 1: - return - error = self.client.plugin['xep_0009']._recpient_unavailable(iq) - error.send() - - def _on_jabber_rpc_error(self, iq, forwarded=False): - """ - A default handler for Jabber-RPC error response. If another - handler is registered, this one will defer and not run. - - If this handler is called by your own custom handler with - forwarded set to True, then it will run as normal. - """ - if not forwarded and self.xmpp.event_handled('jabber_rpc_error') > 1: - return - error = self.client.plugin['xep_0009']._recpient_unavailable(iq, iq.get_payload()) - error.send() - - def _send_fault(self, iq, fault_xml): # - fault = self.make_iq_method_response_fault(iq['id'], iq['from'], fault_xml) - fault.send() - - def _send_error(self, iq): - print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq) - print("#######################") - print("### NOT IMPLEMENTED ###") - print("#######################") - - def _extract_method(self, stanza): - xml = ET.fromstring("%s" % stanza) - return xml.find("./methodCall/methodName").text +""" + Slixmpp: The Slick XMPP Library + Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON). + This file is part of Slixmpp. + + See the file LICENSE for copying permission. +""" + +import logging + +from slixmpp import Iq +from slixmpp.xmlstream import ET, register_stanza_plugin +from slixmpp.xmlstream.handler import Callback +from slixmpp.xmlstream.matcher import MatchXPath +from slixmpp.plugins import BasePlugin +from slixmpp.plugins.xep_0009 import stanza +from slixmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse + + +log = logging.getLogger(__name__) + + +class XEP_0009(BasePlugin): + + name = 'xep_0009' + description = 'XEP-0009: Jabber-RPC' + dependencies = set(['xep_0030']) + stanza = stanza + + def plugin_init(self): + register_stanza_plugin(Iq, RPCQuery) + register_stanza_plugin(RPCQuery, MethodCall) + register_stanza_plugin(RPCQuery, MethodResponse) + + self.xmpp.register_handler( + Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)), + self._handle_method_call) + ) + self.xmpp.register_handler( + Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)), + self._handle_method_response) + ) + self.xmpp.register_handler( + Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)), + self._handle_error) + ) + self.xmpp.add_event_handler('jabber_rpc_method_call', self._on_jabber_rpc_method_call) + self.xmpp.add_event_handler('jabber_rpc_method_response', self._on_jabber_rpc_method_response) + self.xmpp.add_event_handler('jabber_rpc_method_fault', self._on_jabber_rpc_method_fault) + self.xmpp.add_event_handler('jabber_rpc_error', self._on_jabber_rpc_error) + self.xmpp.add_event_handler('error', self._handle_error) + #self.activeCalls = [] + + self.xmpp['xep_0030'].add_feature('jabber:iq:rpc') + self.xmpp['xep_0030'].add_identity('automation','rpc') + + def make_iq_method_call(self, pto, pmethod, params): + iq = self.xmpp.makeIqSet() + iq.attrib['to'] = pto + iq.attrib['from'] = self.xmpp.boundjid.full + iq.enable('rpc_query') + iq['rpc_query']['method_call']['method_name'] = pmethod + iq['rpc_query']['method_call']['params'] = params + return iq; + + def make_iq_method_response(self, pid, pto, params): + iq = self.xmpp.makeIqResult(pid) + iq.attrib['to'] = pto + iq.attrib['from'] = self.xmpp.boundjid.full + iq.enable('rpc_query') + iq['rpc_query']['method_response']['params'] = params + return iq + + def make_iq_method_response_fault(self, pid, pto, params): + iq = self.xmpp.makeIqResult(pid) + iq.attrib['to'] = pto + iq.attrib['from'] = self.xmpp.boundjid.full + iq.enable('rpc_query') + iq['rpc_query']['method_response']['params'] = None + iq['rpc_query']['method_response']['fault'] = params + return iq + +# def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition): +# iq = self.xmpp.makeIqError(pid) +# iq.attrib['to'] = pto +# iq.attrib['from'] = self.xmpp.boundjid.full +# iq['error']['code'] = code +# iq['error']['type'] = type +# iq['error']['condition'] = condition +# iq['rpc_query']['method_call']['method_name'] = pmethod +# iq['rpc_query']['method_call']['params'] = params +# return iq + + def _item_not_found(self, iq): + payload = iq.get_payload() + iq.reply().error().set_payload(payload); + iq['error']['code'] = '404' + iq['error']['type'] = 'cancel' + iq['error']['condition'] = 'item-not-found' + return iq + + def _undefined_condition(self, iq): + payload = iq.get_payload() + iq.reply().error().set_payload(payload) + iq['error']['code'] = '500' + iq['error']['type'] = 'cancel' + iq['error']['condition'] = 'undefined-condition' + return iq + + def _forbidden(self, iq): + payload = iq.get_payload() + iq.reply().error().set_payload(payload) + iq['error']['code'] = '403' + iq['error']['type'] = 'auth' + iq['error']['condition'] = 'forbidden' + return iq + + def _recipient_unvailable(self, iq): + payload = iq.get_payload() + iq.reply().error().set_payload(payload) + iq['error']['code'] = '404' + iq['error']['type'] = 'wait' + iq['error']['condition'] = 'recipient-unavailable' + return iq + + def _handle_method_call(self, iq): + type = iq['type'] + if type == 'set': + log.debug("Incoming Jabber-RPC call from %s", iq['from']) + self.xmpp.event('jabber_rpc_method_call', iq) + else: + if type == 'error' and ['rpc_query'] is None: + self.handle_error(iq) + else: + log.debug("Incoming Jabber-RPC error from %s", iq['from']) + self.xmpp.event('jabber_rpc_error', iq) + + def _handle_method_response(self, iq): + if iq['rpc_query']['method_response']['fault'] is not None: + log.debug("Incoming Jabber-RPC fault from %s", iq['from']) + #self._on_jabber_rpc_method_fault(iq) + self.xmpp.event('jabber_rpc_method_fault', iq) + else: + log.debug("Incoming Jabber-RPC response from %s", iq['from']) + self.xmpp.event('jabber_rpc_method_response', iq) + + def _handle_error(self, iq): + print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq) + print("#######################") + print("### NOT IMPLEMENTED ###") + print("#######################") + + def _on_jabber_rpc_method_call(self, iq, forwarded=False): + """ + A default handler for Jabber-RPC method call. If another + handler is registered, this one will defer and not run. + + If this handler is called by your own custom handler with + forwarded set to True, then it will run as normal. + """ + if not forwarded and self.xmpp.event_handled('jabber_rpc_method_call') > 1: + return + # Reply with error by default + error = self.client.plugin['xep_0009']._item_not_found(iq) + error.send() + + def _on_jabber_rpc_method_response(self, iq, forwarded=False): + """ + A default handler for Jabber-RPC method response. If another + handler is registered, this one will defer and not run. + + If this handler is called by your own custom handler with + forwarded set to True, then it will run as normal. + """ + if not forwarded and self.xmpp.event_handled('jabber_rpc_method_response') > 1: + return + error = self.client.plugin['xep_0009']._recpient_unavailable(iq) + error.send() + + def _on_jabber_rpc_method_fault(self, iq, forwarded=False): + """ + A default handler for Jabber-RPC fault response. If another + handler is registered, this one will defer and not run. + + If this handler is called by your own custom handler with + forwarded set to True, then it will run as normal. + """ + if not forwarded and self.xmpp.event_handled('jabber_rpc_method_fault') > 1: + return + error = self.client.plugin['xep_0009']._recpient_unavailable(iq) + error.send() + + def _on_jabber_rpc_error(self, iq, forwarded=False): + """ + A default handler for Jabber-RPC error response. If another + handler is registered, this one will defer and not run. + + If this handler is called by your own custom handler with + forwarded set to True, then it will run as normal. + """ + if not forwarded and self.xmpp.event_handled('jabber_rpc_error') > 1: + return + error = self.client.plugin['xep_0009']._recpient_unavailable(iq, iq.get_payload()) + error.send() + + def _send_fault(self, iq, fault_xml): # + fault = self.make_iq_method_response_fault(iq['id'], iq['from'], fault_xml) + fault.send() + + def _send_error(self, iq): + print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq) + print("#######################") + print("### NOT IMPLEMENTED ###") + print("#######################") + + def _extract_method(self, stanza): + xml = ET.fromstring("%s" % stanza) + return xml.find("./methodCall/methodName").text diff --git a/slixmpp/plugins/xep_0012/last_activity.py b/slixmpp/plugins/xep_0012/last_activity.py index 36d21b29..76a68c7a 100644 --- a/slixmpp/plugins/xep_0012/last_activity.py +++ b/slixmpp/plugins/xep_0012/last_activity.py @@ -1,156 +1,156 @@ -""" - Slixmpp: The Slick XMPP Library - Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout - This file is part of Slixmpp. - - See the file LICENSE for copying permission. -""" - -import logging -from datetime import datetime, timedelta - -from slixmpp.plugins import BasePlugin, register_plugin -from slixmpp import Iq -from slixmpp.exceptions import XMPPError -from slixmpp.xmlstream import JID, register_stanza_plugin -from slixmpp.xmlstream.handler import Callback -from slixmpp.xmlstream.matcher import StanzaPath -from slixmpp.plugins.xep_0012 import stanza, LastActivity - - -log = logging.getLogger(__name__) - - -class XEP_0012(BasePlugin): - - """ - XEP-0012 Last Activity - """ - - name = 'xep_0012' - description = 'XEP-0012: Last Activity' - dependencies = set(['xep_0030']) - stanza = stanza - - def plugin_init(self): - register_stanza_plugin(Iq, LastActivity) - - self._last_activities = {} - - self.xmpp.register_handler( - Callback('Last Activity', - StanzaPath('iq@type=get/last_activity'), - self._handle_get_last_activity)) - - self.api.register(self._default_get_last_activity, - 'get_last_activity', - default=True) - self.api.register(self._default_set_last_activity, - 'set_last_activity', - default=True) - self.api.register(self._default_del_last_activity, - 'del_last_activity', - default=True) - - def plugin_end(self): - self.xmpp.remove_handler('Last Activity') - self.xmpp['xep_0030'].del_feature(feature='jabber:iq:last') - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature('jabber:iq:last') - - def begin_idle(self, jid=None, status=None): - self.set_last_activity(jid, 0, status) - - def end_idle(self, jid=None): - self.del_last_activity(jid) - - def start_uptime(self, status=None): - self.set_last_activity(jid, 0, status) - - def set_last_activity(self, jid=None, seconds=None, status=None): - self.api['set_last_activity'](jid, args={ - 'seconds': seconds, - 'status': status}) - - def del_last_activity(self, jid): - self.api['del_last_activity'](jid) - - def get_last_activity(self, jid, local=False, ifrom=None, timeout=None, - callback=None, timeout_callback=None): - if jid is not None and not isinstance(jid, JID): - jid = JID(jid) - - if self.xmpp.is_component: - if jid.domain == self.xmpp.boundjid.domain: - local = True - else: - if str(jid) == str(self.xmpp.boundjid): - local = True - jid = jid.full - - if local or jid in (None, ''): - log.debug("Looking up local last activity data for %s", jid) - return self.api['get_last_activity'](jid, None, ifrom, None) - - iq = self.xmpp.Iq() - iq['from'] = ifrom - iq['to'] = jid - iq['type'] = 'get' - iq.enable('last_activity') - return iq.send(timeout=timeout, callback=callback, - timeout_callback=timeout_callback) - - def _handle_get_last_activity(self, iq): - log.debug("Received last activity query from " + \ - "<%s> to <%s>.", iq['from'], iq['to']) - reply = self.api['get_last_activity'](iq['to'], None, iq['from'], iq) - reply.send() - - # ================================================================= - # Default in-memory implementations for storing last activity data. - # ================================================================= - - def _default_set_last_activity(self, jid, node, ifrom, data): - seconds = data.get('seconds', None) - if seconds is None: - seconds = 0 - - status = data.get('status', None) - if status is None: - status = '' - - self._last_activities[jid] = { - 'seconds': datetime.now() - timedelta(seconds=seconds), - 'status': status} - - def _default_del_last_activity(self, jid, node, ifrom, data): - if jid in self._last_activities: - del self._last_activities[jid] - - def _default_get_last_activity(self, jid, node, ifrom, iq): - if not isinstance(iq, Iq): - reply = self.xmpp.Iq() - else: - iq.reply() - reply = iq - - if jid not in self._last_activities: - raise XMPPError('service-unavailable') - - bare = JID(jid).bare - - if bare != self.xmpp.boundjid.bare: - if bare in self.xmpp.roster[jid]: - sub = self.xmpp.roster[jid][bare]['subscription'] - if sub not in ('from', 'both'): - raise XMPPError('forbidden') - - td = datetime.now() - self._last_activities[jid]['seconds'] - seconds = td.seconds + td.days * 24 * 3600 - status = self._last_activities[jid]['status'] - - reply['last_activity']['seconds'] = seconds - reply['last_activity']['status'] = status - - return reply +""" + Slixmpp: The Slick XMPP Library + Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout + This file is part of Slixmpp. + + See the file LICENSE for copying permission. +""" + +import logging +from datetime import datetime, timedelta + +from slixmpp.plugins import BasePlugin, register_plugin +from slixmpp import Iq +from slixmpp.exceptions import XMPPError +from slixmpp.xmlstream import JID, register_stanza_plugin +from slixmpp.xmlstream.handler import Callback +from slixmpp.xmlstream.matcher import StanzaPath +from slixmpp.plugins.xep_0012 import stanza, LastActivity + + +log = logging.getLogger(__name__) + + +class XEP_0012(BasePlugin): + + """ + XEP-0012 Last Activity + """ + + name = 'xep_0012' + description = 'XEP-0012: Last Activity' + dependencies = set(['xep_0030']) + stanza = stanza + + def plugin_init(self): + register_stanza_plugin(Iq, LastActivity) + + self._last_activities = {} + + self.xmpp.register_handler( + Callback('Last Activity', + StanzaPath('iq@type=get/last_activity'), + self._handle_get_last_activity)) + + self.api.register(self._default_get_last_activity, + 'get_last_activity', + default=True) + self.api.register(self._default_set_last_activity, + 'set_last_activity', + default=True) + self.api.register(self._default_del_last_activity, + 'del_last_activity', + default=True) + + def plugin_end(self): + self.xmpp.remove_handler('Last Activity') + self.xmpp['xep_0030'].del_feature(feature='jabber:iq:last') + + def session_bind(self, jid): + self.xmpp['xep_0030'].add_feature('jabber:iq:last') + + def begin_idle(self, jid=None, status=None): + self.set_last_activity(jid, 0, status) + + def end_idle(self, jid=None): + self.del_last_activity(jid) + + def start_uptime(self, status=None): + self.set_last_activity(jid, 0, status) + + def set_last_activity(self, jid=None, seconds=None, status=None): + self.api['set_last_activity'](jid, args={ + 'seconds': seconds, + 'status': status}) + + def del_last_activity(self, jid): + self.api['del_last_activity'](jid) + + def get_last_activity(self, jid, local=False, ifrom=None, timeout=None, + callback=None, timeout_callback=None): + if jid is not None and not isinstance(jid, JID): + jid = JID(jid) + + if self.xmpp.is_component: + if jid.domain == self.xmpp.boundjid.domain: + local = True + else: + if str(jid) == str(self.xmpp.boundjid): + local = True + jid = jid.full + + if local or jid in (None, ''): + log.debug("Looking up local last activity data for %s", jid) + return self.api['get_last_activity'](jid, None, ifrom, None) + + iq = self.xmpp.Iq() + iq['from'] = ifrom + iq['to'] = jid + iq['type'] = 'get' + iq.enable('last_activity') + return iq.send(timeout=timeout, callback=callback, + timeout_callback=timeout_callback) + + def _handle_get_last_activity(self, iq): + log.debug("Received last activity query from " + \ + "<%s> to <%s>.", iq['from'], iq['to']) + reply = self.api['get_last_activity'](iq['to'], None, iq['from'], iq) + reply.send() + + # ================================================================= + # Default in-memory implementations for storing last activity data. + # ================================================================= + + def _default_set_last_activity(self, jid, node, ifrom, data): + seconds = data.get('seconds', None) + if seconds is None: + seconds = 0 + + status = data.get('status', None) + if status is None: + status = '' + + self._last_activities[jid] = { + 'seconds': datetime.now() - timedelta(seconds=seconds), + 'status': status} + + def _default_del_last_activity(self, jid, node, ifrom, data): + if jid in self._last_activities: + del self._last_activities[jid] + + def _default_get_last_activity(self, jid, node, ifrom, iq): + if not isinstance(iq, Iq): + reply = self.xmpp.Iq() + else: + iq.reply() + reply = iq + + if jid not in self._last_activities: + raise XMPPError('service-unavailable') + + bare = JID(jid).bare + + if bare != self.xmpp.boundjid.bare: + if bare in self.xmpp.roster[jid]: + sub = self.xmpp.roster[jid][bare]['subscription'] + if sub not in ('from', 'both'): + raise XMPPError('forbidden') + + td = datetime.now() - self._last_activities[jid]['seconds'] + seconds = td.seconds + td.days * 24 * 3600 + status = self._last_activities[jid]['status'] + + reply['last_activity']['seconds'] = seconds + reply['last_activity']['status'] = status + + return reply diff --git a/slixmpp/plugins/xep_0045.py b/slixmpp/plugins/xep_0045.py index 5950ab1b..66693734 100644 --- a/slixmpp/plugins/xep_0045.py +++ b/slixmpp/plugins/xep_0045.py @@ -307,7 +307,7 @@ class XEP_0045(BasePlugin): if role not in ('moderator', 'participant', 'visitor', 'none'): raise TypeError query = ET.Element('{http://jabber.org/protocol/muc#admin}query') - item = ET.Element('item', {'role':role, 'nick':nick}) + item = ET.Element('item', {'role':role, 'nick':nick}) query.append(item) iq = self.xmpp.makeIqSet(query) iq['to'] = room diff --git a/slixmpp/plugins/xep_0065/proxy.py b/slixmpp/plugins/xep_0065/proxy.py index 654d9dce..818b0cb2 100644 --- a/slixmpp/plugins/xep_0065/proxy.py +++ b/slixmpp/plugins/xep_0065/proxy.py @@ -206,7 +206,7 @@ class XEP_0065(base_plugin): # Though this should not be neccessary remove the closed session anyway with self._sessions_lock: if sid in self._sessions: - log.warn(('SOCKS5 session with sid = "%s" was not ' + + log.warn(('SOCKS5 session with sid = "%s" was not ' + 'removed from _sessions by sock.close()') % sid) del self._sessions[sid] diff --git a/slixmpp/plugins/xep_0086/legacy_error.py b/slixmpp/plugins/xep_0086/legacy_error.py index d56c4dbf..0a6e0e87 100644 --- a/slixmpp/plugins/xep_0086/legacy_error.py +++ b/slixmpp/plugins/xep_0086/legacy_error.py @@ -1,46 +1,46 @@ -""" - Slixmpp: The Slick XMPP Library - Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout - This file is part of Slixmpp. - - See the file LICENSE for copying permission. -""" - -from slixmpp.stanza import Error -from slixmpp.xmlstream import register_stanza_plugin -from slixmpp.plugins import BasePlugin -from slixmpp.plugins.xep_0086 import stanza, LegacyError - - -class XEP_0086(BasePlugin): - - """ - XEP-0086: Error Condition Mappings - - Older XMPP implementations used code based error messages, similar - to HTTP response codes. Since then, error condition elements have - been introduced. XEP-0086 provides a mapping between the new - condition elements and a combination of error types and the older - response codes. - - Also see . - - Configuration Values: - override -- Indicates if applying legacy error codes should - be done automatically. Defaults to True. - If False, then inserting legacy error codes can - be done using: - iq['error']['legacy']['condition'] = ... - """ - - name = 'xep_0086' - description = 'XEP-0086: Error Condition Mappings' - dependencies = set() - stanza = stanza - default_config = { - 'override': True - } - - def plugin_init(self): - register_stanza_plugin(Error, LegacyError, - overrides=self.override) +""" + Slixmpp: The Slick XMPP Library + Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout + This file is part of Slixmpp. + + See the file LICENSE for copying permission. +""" + +from slixmpp.stanza import Error +from slixmpp.xmlstream import register_stanza_plugin +from slixmpp.plugins import BasePlugin +from slixmpp.plugins.xep_0086 import stanza, LegacyError + + +class XEP_0086(BasePlugin): + + """ + XEP-0086: Error Condition Mappings + + Older XMPP implementations used code based error messages, similar + to HTTP response codes. Since then, error condition elements have + been introduced. XEP-0086 provides a mapping between the new + condition elements and a combination of error types and the older + response codes. + + Also see . + + Configuration Values: + override -- Indicates if applying legacy error codes should + be done automatically. Defaults to True. + If False, then inserting legacy error codes can + be done using: + iq['error']['legacy']['condition'] = ... + """ + + name = 'xep_0086' + description = 'XEP-0086: Error Condition Mappings' + dependencies = set() + stanza = stanza + default_config = { + 'override': True + } + + def plugin_init(self): + register_stanza_plugin(Error, LegacyError, + overrides=self.override) diff --git a/slixmpp/plugins/xep_0153/vcard_avatar.py b/slixmpp/plugins/xep_0153/vcard_avatar.py index 0220dfec..c46999e3 100644 --- a/slixmpp/plugins/xep_0153/vcard_avatar.py +++ b/slixmpp/plugins/xep_0153/vcard_avatar.py @@ -129,7 +129,7 @@ class XEP_0153(BasePlugin): # Don't process vCard avatars for MUC occupants # since they all share the same bare JID. return - except: pass + except: pass if not pres.match('presence/vcard_temp_update'): self.api['set_hash'](pres['from'], args=None) diff --git a/slixmpp/plugins/xep_0202/time.py b/slixmpp/plugins/xep_0202/time.py index 3b335e28..760ef26a 100644 --- a/slixmpp/plugins/xep_0202/time.py +++ b/slixmpp/plugins/xep_0202/time.py @@ -1,98 +1,98 @@ -""" - Slixmpp: The Slick XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of Slixmpp. - - See the file LICENSE for copying permission. -""" - -import logging - -from slixmpp.stanza.iq import Iq -from slixmpp.xmlstream import register_stanza_plugin -from slixmpp.xmlstream.handler import Callback -from slixmpp.xmlstream.matcher import StanzaPath -from slixmpp.plugins import BasePlugin -from slixmpp.plugins import xep_0082 -from slixmpp.plugins.xep_0202 import stanza - - -log = logging.getLogger(__name__) - - -class XEP_0202(BasePlugin): - - """ - XEP-0202: Entity Time - """ - - name = 'xep_0202' - description = 'XEP-0202: Entity Time' - dependencies = set(['xep_0030', 'xep_0082']) - stanza = stanza - default_config = { - #: As a default, respond to time requests with the - #: local time returned by XEP-0082. However, a - #: custom function can be supplied which accepts - #: the JID of the entity to query for the time. - 'local_time': None, - 'tz_offset': 0 - } - - def plugin_init(self): - """Start the XEP-0203 plugin.""" - - if not self.local_time: - def default_local_time(jid): - return xep_0082.datetime(offset=self.tz_offset) - - self.local_time = default_local_time - - self.xmpp.register_handler( - Callback('Entity Time', - StanzaPath('iq/entity_time'), - self._handle_time_request)) - register_stanza_plugin(Iq, stanza.EntityTime) - - def plugin_end(self): - self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:time') - self.xmpp.remove_handler('Entity Time') - - def session_bind(self, jid): - self.xmpp['xep_0030'].add_feature('urn:xmpp:time') - - def _handle_time_request(self, iq): - """ - Respond to a request for the local time. - - The time is taken from self.local_time(), which may be replaced - during plugin configuration with a function that maps JIDs to - times. - - Arguments: - iq -- The Iq time request stanza. - """ - iq.reply() - iq['entity_time']['time'] = self.local_time(iq['to']) - iq.send() - - def get_entity_time(self, to, ifrom=None, **iqargs): - """ - Request the time from another entity. - - Arguments: - to -- JID of the entity to query. - ifrom -- Specifiy the sender's JID. - block -- If true, block and wait for the stanzas' reply. - timeout -- The time in seconds to block while waiting for - a reply. If None, then wait indefinitely. - callback -- Optional callback to execute when a reply is - received instead of blocking and waiting for - the reply. - """ - iq = self.xmpp.Iq() - iq['type'] = 'get' - iq['to'] = to - iq['from'] = ifrom - iq.enable('entity_time') - return iq.send(**iqargs) +""" + Slixmpp: The Slick XMPP Library + Copyright (C) 2010 Nathanael C. Fritz + This file is part of Slixmpp. + + See the file LICENSE for copying permission. +""" + +import logging + +from slixmpp.stanza.iq import Iq +from slixmpp.xmlstream import register_stanza_plugin +from slixmpp.xmlstream.handler import Callback +from slixmpp.xmlstream.matcher import StanzaPath +from slixmpp.plugins import BasePlugin +from slixmpp.plugins import xep_0082 +from slixmpp.plugins.xep_0202 import stanza + + +log = logging.getLogger(__name__) + + +class XEP_0202(BasePlugin): + + """ + XEP-0202: Entity Time + """ + + name = 'xep_0202' + description = 'XEP-0202: Entity Time' + dependencies = set(['xep_0030', 'xep_0082']) + stanza = stanza + default_config = { + #: As a default, respond to time requests with the + #: local time returned by XEP-0082. However, a + #: custom function can be supplied which accepts + #: the JID of the entity to query for the time. + 'local_time': None, + 'tz_offset': 0 + } + + def plugin_init(self): + """Start the XEP-0203 plugin.""" + + if not self.local_time: + def default_local_time(jid): + return xep_0082.datetime(offset=self.tz_offset) + + self.local_time = default_local_time + + self.xmpp.register_handler( + Callback('Entity Time', + StanzaPath('iq/entity_time'), + self._handle_time_request)) + register_stanza_plugin(Iq, stanza.EntityTime) + + def plugin_end(self): + self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:time') + self.xmpp.remove_handler('Entity Time') + + def session_bind(self, jid): + self.xmpp['xep_0030'].add_feature('urn:xmpp:time') + + def _handle_time_request(self, iq): + """ + Respond to a request for the local time. + + The time is taken from self.local_time(), which may be replaced + during plugin configuration with a function that maps JIDs to + times. + + Arguments: + iq -- The Iq time request stanza. + """ + iq.reply() + iq['entity_time']['time'] = self.local_time(iq['to']) + iq.send() + + def get_entity_time(self, to, ifrom=None, **iqargs): + """ + Request the time from another entity. + + Arguments: + to -- JID of the entity to query. + ifrom -- Specifiy the sender's JID. + block -- If true, block and wait for the stanzas' reply. + timeout -- The time in seconds to block while waiting for + a reply. If None, then wait indefinitely. + callback -- Optional callback to execute when a reply is + received instead of blocking and waiting for + the reply. + """ + iq = self.xmpp.Iq() + iq['type'] = 'get' + iq['to'] = to + iq['from'] = ifrom + iq.enable('entity_time') + return iq.send(**iqargs) diff --git a/slixmpp/plugins/xep_0323/device.py b/slixmpp/plugins/xep_0323/device.py index a3bd95d7..592cac75 100644 --- a/slixmpp/plugins/xep_0323/device.py +++ b/slixmpp/plugins/xep_0323/device.py @@ -13,9 +13,9 @@ import logging class Device(object): """ - Example implementation of a device readout object. + Example implementation of a device readout object. Is registered in the XEP_0323.register_node call - The device object may be any custom implementation to support + The device object may be any custom implementation to support specific devices, but it must implement the functions: has_field request_fields @@ -38,19 +38,19 @@ class Device(object): Returns true if the supplied field name exists in this device. Arguments: - field -- The field name + field -- The field name """ if field in self.fields.keys(): return True; return False; - + def refresh(self, fields): """ override method to do the refresh work refresh values from hardware or other """ pass - + def request_fields(self, fields, flags, session, callback): """ @@ -65,7 +65,7 @@ class Device(object): Formatted as a dictionary like { "flag name": "flag value" ... } session -- Session id, only used in the callback as identifier callback -- Callback function to call when data is available. - + The callback function must support the following arguments: session -- Session id, as supplied in the request_fields call @@ -73,11 +73,11 @@ class Device(object): result -- The current result status of the readout. Valid values are: "error" - Readout failed. "fields" - Contains readout data. - "done" - Indicates that the readout is complete. May contain + "done" - Indicates that the readout is complete. May contain readout data. - timestamp_block -- [optional] Only applies when result != "error" + timestamp_block -- [optional] Only applies when result != "error" The readout data. Structured as a dictionary: - { + { timestamp: timestamp for this datablock, fields: list of field dictionary (one per readout field). readout field dictionary format: @@ -89,10 +89,10 @@ class Device(object): dataType: The datatype of the field. Only applies to type enum. flags: [optional] data classifier flags for the field, e.g. momentary Formatted as a dictionary like { "flag name": "flag value" ... } - } + } } error_msg -- [optional] Only applies when result == "error". - Error details when a request failed. + Error details when a request failed. """ logging.debug("request_fields called looking for fields %s",fields) @@ -125,11 +125,11 @@ class Device(object): field_block = []; for f in self.momentary_data: if f in fields: - field_block.append({"name": f, - "type": self.fields[f]["type"], + field_block.append({"name": f, + "type": self.fields[f]["type"], "unit": self.fields[f]["unit"], "dataType": self.fields[f]["dataType"], - "value": self.momentary_data[f]["value"], + "value": self.momentary_data[f]["value"], "flags": self.momentary_data[f]["flags"]}); ts_block["timestamp"] = timestamp; ts_block["fields"] = field_block; @@ -142,25 +142,25 @@ class Device(object): for ts in sorted(self.timestamp_data.keys()): tsdt = datetime.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%S") - if not from_flag is None: - if tsdt < from_flag: + if not from_flag is None: + if tsdt < from_flag: #print (str(tsdt) + " < " + str(from_flag)) continue - if not to_flag is None: - if tsdt > to_flag: + if not to_flag is None: + if tsdt > to_flag: #print (str(tsdt) + " > " + str(to_flag)) continue - + ts_block = {}; field_block = []; for f in self.timestamp_data[ts]: if f in fields: - field_block.append({"name": f, - "type": self.fields[f]["type"], + field_block.append({"name": f, + "type": self.fields[f]["type"], "unit": self.fields[f]["unit"], "dataType": self.fields[f]["dataType"], - "value": self.timestamp_data[ts][f]["value"], + "value": self.timestamp_data[ts][f]["value"], "flags": self.timestamp_data[ts][f]["flags"]}); ts_block["timestamp"] = ts; @@ -171,7 +171,7 @@ class Device(object): def _datetime_flag_parser(self, flags, flagname): if not flagname in flags: return None - + dt = None try: dt = datetime.datetime.strptime(flags[flagname], "%Y-%m-%dT%H:%M:%S") @@ -242,7 +242,7 @@ class Device(object): return False; if flags is None: flags = {}; - + flags["momentary"] = "true" self.momentary_data[name] = {"value": value, "flags": flags}; return True; diff --git a/slixmpp/plugins/xep_0323/sensordata.py b/slixmpp/plugins/xep_0323/sensordata.py index afb694d0..41a3b58d 100644 --- a/slixmpp/plugins/xep_0323/sensordata.py +++ b/slixmpp/plugins/xep_0323/sensordata.py @@ -29,12 +29,12 @@ log = logging.getLogger(__name__) class XEP_0323(BasePlugin): """ - XEP-0323: IoT Sensor Data + XEP-0323: IoT Sensor Data This XEP provides the underlying architecture, basic operations and data structures for sensor data communication over XMPP networks. It includes - a hardware abstraction model, removing any technical detail implemented + a hardware abstraction model, removing any technical detail implemented in underlying technologies. Also see @@ -55,10 +55,10 @@ class XEP_0323(BasePlugin): Sensordata Event:Rejected -- Received a reject from sensor for a request Sensordata Event:Cancelled -- Received a cancel confirm from sensor Sensordata Event:Fields -- Received fields from sensor for a request - This may be triggered multiple times since + This may be triggered multiple times since the sensor can split up its response in multiple messages. - Sensordata Event:Failure -- Received a failure indication from sensor + Sensordata Event:Failure -- Received a failure indication from sensor for a request. Typically a comm timeout. Attributes: @@ -69,7 +69,7 @@ class XEP_0323(BasePlugin): relevant to a request's session. This dictionary is used both by the client and sensor side. On client side, seqnr is used as key, while on sensor side, a session_id is used - as key. This ensures that the two will not collide, so + as key. This ensures that the two will not collide, so one instance can be both client and sensor. Sensor side ----------- @@ -89,12 +89,12 @@ class XEP_0323(BasePlugin): Sensor side ----------- - register_node -- Register a sensor as available from this XMPP + register_node -- Register a sensor as available from this XMPP instance. Client side ----------- - request_data -- Initiates a request for data from one or more + request_data -- Initiates a request for data from one or more sensors. Non-blocking, a callback function will be called when data is available. @@ -102,7 +102,7 @@ class XEP_0323(BasePlugin): name = 'xep_0323' description = 'XEP-0323 Internet of Things - Sensor Data' - dependencies = set(['xep_0030']) + dependencies = set(['xep_0030']) stanza = stanza @@ -198,9 +198,9 @@ class XEP_0323(BasePlugin): def register_node(self, nodeId, device, commTimeout, sourceId=None, cacheType=None): """ Register a sensor/device as available for serving of data through this XMPP - instance. + instance. - The device object may by any custom implementation to support + The device object may by any custom implementation to support specific devices, but it must implement the functions: has_field request_fields @@ -212,11 +212,11 @@ class XEP_0323(BasePlugin): commTimeout -- Time in seconds to wait between each callback from device during a data readout. Float. sourceId -- [optional] identifying the data source controlling the device - cacheType -- [optional] narrowing down the search to a specific kind of node + cacheType -- [optional] narrowing down the search to a specific kind of node """ - self.nodes[nodeId] = {"device": device, + self.nodes[nodeId] = {"device": device, "commTimeout": commTimeout, - "sourceId": sourceId, + "sourceId": sourceId, "cacheType": cacheType}; def _set_authenticated(self, auth=''): @@ -228,9 +228,9 @@ class XEP_0323(BasePlugin): """ Event handler for reception of an Iq with req - this is a request. - Verifies that + Verifies that - all the requested nodes are available - - at least one of the requested fields is available from at least + - at least one of the requested fields is available from at least one of the nodes If the request passes verification, an accept response is sent, and @@ -331,12 +331,12 @@ class XEP_0323(BasePlugin): iq['type'] = 'error'; iq['rejected']['seqnr'] = seqnr; iq['rejected']['error'] = error_msg; - iq.send(block=False); + iq.send(block=False); def _threaded_node_request(self, session, process_fields, flags): - """ + """ Helper function to handle the device readouts in a separate thread. - + Arguments: session -- The request session id process_fields -- The fields to request from the devices @@ -344,7 +344,7 @@ class XEP_0323(BasePlugin): Formatted as a dictionary like { "flag name": "flag value" ... } """ for node in self.sessions[session]["node_list"]: - self.sessions[session]["nodeDone"][node] = False; + self.sessions[session]["nodeDone"][node] = False; for node in self.sessions[session]["node_list"]: timer = TimerReset(self.nodes[node]['commTimeout'], self._event_comm_timeout, args=(session, node)); @@ -354,11 +354,11 @@ class XEP_0323(BasePlugin): self.nodes[node]['device'].request_fields(process_fields, flags=flags, session=session, callback=self._device_field_request_callback); def _event_comm_timeout(self, session, nodeId): - """ + """ Triggered if any of the readout operations timeout. Sends a failure message back to the client, stops communicating with the failing device. - + Arguments: session -- The request session id nodeId -- The id of the device which timed out @@ -366,7 +366,7 @@ class XEP_0323(BasePlugin): msg = self.xmpp.Message(); msg['from'] = self.sessions[session]['to']; msg['to'] = self.sessions[session]['from']; - msg['failure']['seqnr'] = self.sessions[session]['seqnr']; + msg['failure']['seqnr'] = self.sessions[session]['seqnr']; msg['failure']['error']['text'] = "Timeout"; msg['failure']['error']['nodeId'] = nodeId; msg['failure']['error']['timestamp'] = datetime.datetime.now().replace(microsecond=0).isoformat(); @@ -403,9 +403,9 @@ class XEP_0323(BasePlugin): self._threaded_node_request(session, process_fields, req_flags); def _all_nodes_done(self, session): - """ + """ Checks wheter all devices are done replying to the readout. - + Arguments: session -- The request session id """ @@ -415,22 +415,22 @@ class XEP_0323(BasePlugin): return True; def _device_field_request_callback(self, session, nodeId, result, timestamp_block, error_msg=None): - """ + """ Callback function called by the devices when they have any additional data. - Composes a message with the data and sends it back to the client, and resets + Composes a message with the data and sends it back to the client, and resets the timeout timer for the device. - + Arguments: session -- The request session id nodeId -- The device id which initiated the callback result -- The current result status of the readout. Valid values are: "error" - Readout failed. "fields" - Contains readout data. - "done" - Indicates that the readout is complete. May contain + "done" - Indicates that the readout is complete. May contain readout data. - timestamp_block -- [optional] Only applies when result != "error" + timestamp_block -- [optional] Only applies when result != "error" The readout data. Structured as a dictionary: - { + { timestamp: timestamp for this datablock, fields: list of field dictionary (one per readout field). readout field dictionary format: @@ -442,7 +442,7 @@ class XEP_0323(BasePlugin): dataType: The datatype of the field. Only applies to type enum. flags: [optional] data classifier flags for the field, e.g. momentary Formatted as a dictionary like { "flag name": "flag value" ... } - } + } } error_msg -- [optional] Only applies when result == "error". Error details when a request failed. @@ -463,7 +463,7 @@ class XEP_0323(BasePlugin): msg['failure']['error']['timestamp'] = datetime.datetime.now().replace(microsecond=0).isoformat(); # Drop communication with this device and check if we are done - self.sessions[session]["nodeDone"][nodeId] = True; + self.sessions[session]["nodeDone"][nodeId] = True; if (self._all_nodes_done(session)): msg['failure']['done'] = 'true'; # The session is complete, delete it @@ -481,11 +481,11 @@ class XEP_0323(BasePlugin): ts = node.add_timestamp(timestamp_block["timestamp"]); for f in timestamp_block["fields"]: - data = ts.add_data( typename=f['type'], - name=f['name'], - value=f['value'], - unit=f['unit'], - dataType=f['dataType'], + data = ts.add_data( typename=f['type'], + name=f['name'], + value=f['value'], + unit=f['unit'], + dataType=f['dataType'], flags=f['flags']); if result == "done": @@ -503,7 +503,7 @@ class XEP_0323(BasePlugin): msg.send(); def _handle_event_cancel(self, iq): - """ Received Iq with cancel - this is a cancel request. + """ Received Iq with cancel - this is a cancel request. Delete the session and confirm. """ seqnr = iq['cancel']['seqnr']; @@ -518,8 +518,8 @@ class XEP_0323(BasePlugin): iq.reply(); iq['type'] = 'result'; iq['cancelled']['seqnr'] = seqnr; - iq.send(block=False); - + iq.send(block=False); + # Delete session del self.sessions[s] return @@ -529,22 +529,22 @@ class XEP_0323(BasePlugin): iq['type'] = 'error'; iq['rejected']['seqnr'] = seqnr; iq['rejected']['error'] = "Cancel request received, no matching request is active."; - iq.send(block=False); + iq.send(block=False); # ================================================================= # 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. 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 availble. + The callback function must support the following arguments: from_jid -- The jid of the responding device(s) @@ -565,7 +565,7 @@ class XEP_0323(BasePlugin): The timestamp of data in this callback. One callback will only contain data from one timestamp. fields -- [optional] Mandatory when result == "fields". - List of field dictionaries representing the readout data. + List of field dictionaries representing the readout data. Dictionary format: { typename: The field type (numeric, boolean, dateTime, timeSpan, string, enum) @@ -575,11 +575,11 @@ class XEP_0323(BasePlugin): dataType: The datatype of the field. Only applies to type enum. flags: [optional] data classifier flags for the field, e.g. momentary. Formatted as a dictionary like { "flag name": "flag value" ... } - } + } error_msg -- [optional] Mandatory when result == "rejected" or "failure". - Details about why the request is rejected or failed. - "rejected" means that the request is stopped, but note that the + Details about why the request is rejected or failed. + "rejected" means that the request is stopped, but note that the request will continue even after a "failure". "failure" only means that communication was stopped to that specific device, other device(s) (if any) will continue their readout. @@ -610,17 +610,17 @@ class XEP_0323(BasePlugin): iq['req']._set_flags(flags); self.sessions[seqnr] = {"from": iq['from'], "to": iq['to'], "seqnr": seqnr, "callback": callback}; - iq.send(block=False); + iq.send(block=False); return seqnr; def cancel_request(self, session): - """ + """ Called on the client side to cancel a request for data readout. Composes a message with the cancellation and sends it to the device(s). - Does not block, the callback will be called when cancellation is + Does not block, the callback will be called when cancellation is confirmed. - + Arguments: session -- The session id of the request to cancel """ @@ -651,7 +651,7 @@ class XEP_0323(BasePlugin): callback(from_jid=iq['from'], result=result); def _handle_event_rejected(self, iq): - """ Received Iq with rejected - this is a reject. + """ Received Iq with rejected - this is a reject. Delete the session. """ seqnr = iq['rejected']['seqnr']; callback = self.sessions[seqnr]["callback"]; @@ -660,9 +660,9 @@ class XEP_0323(BasePlugin): del self.sessions[seqnr]; def _handle_event_cancelled(self, iq): - """ - Received Iq with cancelled - this is a cancel confirm. - Delete the session. + """ + Received Iq with cancelled - this is a cancel confirm. + Delete the session. """ #print("Got cancelled") seqnr = iq['cancelled']['seqnr']; @@ -672,7 +672,7 @@ class XEP_0323(BasePlugin): del self.sessions[seqnr]; def _handle_event_fields(self, msg): - """ + """ Received Msg with fields - this is a data reponse to a request. If this is the last data block, issue a "done" callback. """ @@ -694,16 +694,16 @@ class XEP_0323(BasePlugin): fields.append(field_block); callback(from_jid=msg['from'], result="fields", nodeId=node['nodeId'], timestamp=ts['value'], fields=fields); - + if msg['fields']['done'] == "true": callback(from_jid=msg['from'], result="done"); # Session done del self.sessions[seqnr]; def _handle_event_failure(self, msg): - """ + """ Received Msg with failure - our request failed - Delete the session. + Delete the session. """ seqnr = msg['failure']['seqnr']; callback = self.sessions[seqnr]["callback"]; @@ -713,11 +713,11 @@ class XEP_0323(BasePlugin): del self.sessions[seqnr]; def _handle_event_started(self, msg): - """ - Received Msg with started - our request was queued and is now started. + """ + Received Msg with started - our request was queued and is now started. """ seqnr = msg['started']['seqnr']; callback = self.sessions[seqnr]["callback"]; callback(from_jid=msg['from'], result="started"); - + diff --git a/slixmpp/plugins/xep_0323/stanza/sensordata.py b/slixmpp/plugins/xep_0323/stanza/sensordata.py index 92946498..eb08975c 100644 --- a/slixmpp/plugins/xep_0323/stanza/sensordata.py +++ b/slixmpp/plugins/xep_0323/stanza/sensordata.py @@ -20,14 +20,14 @@ class Sensordata(ElementBase): interfaces = set(tuple()) class FieldTypes(): - """ + """ All field types are optional booleans that default to False """ field_types = set([ 'momentary','peak','status','computed','identity','historicalSecond','historicalMinute','historicalHour', \ 'historicalDay','historicalWeek','historicalMonth','historicalQuarter','historicalYear','historicalOther']) class FieldStatus(): - """ + """ All field statuses are optional booleans that default to False """ field_status = set([ 'missing','automaticEstimate','manualEstimate','manualReadout','automaticReadout','timeOffset','warning','error', \ @@ -41,7 +41,7 @@ class Request(ElementBase): interfaces.update(FieldTypes.field_types); _flags = set(['serviceToken','deviceToken','userToken','from','to','when','historical','all']); _flags.update(FieldTypes.field_types); - + def __init__(self, xml=None, parent=None): ElementBase.__init__(self, xml, parent); self._nodes = set() @@ -64,8 +64,8 @@ class Request(ElementBase): def _get_flags(self): """ - Helper function for getting of flags. Returns all flags in - dictionary format: { "flag name": "flag value" ... } + Helper function for getting of flags. Returns all flags in + dictionary format: { "flag name": "flag value" ... } """ flags = {}; for f in self._flags: @@ -75,10 +75,10 @@ class Request(ElementBase): def _set_flags(self, flags): """ - Helper function for setting of flags. + Helper function for setting of flags. Arguments: - flags -- Flags in dictionary format: { "flag name": "flag value" ... } + flags -- Flags in dictionary format: { "flag name": "flag value" ... } """ for f in self._flags: if flags is not None and f in flags: @@ -94,7 +94,7 @@ class Request(ElementBase): Arguments: nodeId -- The ID for the node. sourceId -- [optional] identifying the data source controlling the device - cacheType -- [optional] narrowing down the search to a specific kind of node + cacheType -- [optional] narrowing down the search to a specific kind of node """ if nodeId not in self._nodes: self._nodes.add((nodeId)) @@ -318,7 +318,7 @@ class Fields(ElementBase): Arguments: nodeId -- The ID for the node. sourceId -- [optional] identifying the data source controlling the device - cacheType -- [optional] narrowing down the search to a specific kind of node + cacheType -- [optional] narrowing down the search to a specific kind of node """ if nodeId not in self._nodes: self._nodes.add((nodeId)) @@ -411,7 +411,7 @@ class FieldsNode(ElementBase): def add_timestamp(self, timestamp, substanzas=None): """ - Add a new timestamp element. + Add a new timestamp element. Arguments: timestamp -- The timestamp in ISO format. @@ -485,7 +485,7 @@ class FieldsNode(ElementBase): self.iterables.remove(timestamp) class Field(ElementBase): - """ + """ Field element in response Timestamp. This is a base class, all instances of fields added to Timestamp must be of types: DataNumeric @@ -494,7 +494,7 @@ class Field(ElementBase): DataDateTime DataTimeSpan DataEnum - """ + """ namespace = 'urn:xmpp:iot:sensordata' name = 'field' plugin_attrib = name @@ -523,8 +523,8 @@ class Field(ElementBase): def _get_flags(self): """ - Helper function for getting of flags. Returns all flags in - dictionary format: { "flag name": "flag value" ... } + Helper function for getting of flags. Returns all flags in + dictionary format: { "flag name": "flag value" ... } """ flags = {}; for f in self._flags: @@ -534,10 +534,10 @@ class Field(ElementBase): def _set_flags(self, flags): """ - Helper function for setting of flags. + Helper function for setting of flags. Arguments: - flags -- Flags in dictionary format: { "flag name": "flag value" ... } + flags -- Flags in dictionary format: { "flag name": "flag value" ... } """ for f in self._flags: if flags is not None and f in flags: @@ -576,7 +576,7 @@ class Timestamp(ElementBase): def add_data(self, typename, name, value, module=None, stringIds=None, unit=None, dataType=None, flags=None): """ - Add a new data element. + Add a new data element. Arguments: typename -- The type of data element (numeric, string, boolean, dateTime, timeSpan or enum) @@ -661,9 +661,9 @@ class Timestamp(ElementBase): self.iterables.remove(data) class DataNumeric(Field): - """ - Field data of type numeric. - Note that the value is expressed as a string. + """ + Field data of type numeric. + Note that the value is expressed as a string. """ namespace = 'urn:xmpp:iot:sensordata' name = 'numeric' @@ -672,11 +672,11 @@ class DataNumeric(Field): interfaces.update(Field.interfaces); def _get_typename(self): - return "numeric" + return "numeric" class DataString(Field): - """ - Field data of type string + """ + Field data of type string """ namespace = 'urn:xmpp:iot:sensordata' name = 'string' @@ -685,12 +685,12 @@ class DataString(Field): interfaces.update(Field.interfaces); def _get_typename(self): - return "string" + return "string" class DataBoolean(Field): - """ + """ Field data of type boolean. - Note that the value is expressed as a string. + Note that the value is expressed as a string. """ namespace = 'urn:xmpp:iot:sensordata' name = 'boolean' @@ -699,12 +699,12 @@ class DataBoolean(Field): interfaces.update(Field.interfaces); def _get_typename(self): - return "boolean" + return "boolean" class DataDateTime(Field): - """ + """ Field data of type dateTime. - Note that the value is expressed as a string. + Note that the value is expressed as a string. """ namespace = 'urn:xmpp:iot:sensordata' name = 'dateTime' @@ -713,12 +713,12 @@ class DataDateTime(Field): interfaces.update(Field.interfaces); def _get_typename(self): - return "dateTime" + return "dateTime" class DataTimeSpan(Field): - """ + """ Field data of type timeSpan. - Note that the value is expressed as a string. + Note that the value is expressed as a string. """ namespace = 'urn:xmpp:iot:sensordata' name = 'timeSpan' @@ -727,12 +727,12 @@ class DataTimeSpan(Field): interfaces.update(Field.interfaces); def _get_typename(self): - return "timeSpan" + return "timeSpan" class DataEnum(Field): - """ + """ Field data of type enum. - Note that the value is expressed as a string. + Note that the value is expressed as a string. """ namespace = 'urn:xmpp:iot:sensordata' name = 'enum' @@ -741,7 +741,7 @@ class DataEnum(Field): interfaces.update(Field.interfaces); def _get_typename(self): - return "enum" + return "enum" class Done(ElementBase): """ Done element used to signal that all data has been transferred """ diff --git a/slixmpp/plugins/xep_0325/control.py b/slixmpp/plugins/xep_0325/control.py index b1910c57..e83bd31d 100644 --- a/slixmpp/plugins/xep_0325/control.py +++ b/slixmpp/plugins/xep_0325/control.py @@ -26,16 +26,16 @@ log = logging.getLogger(__name__) class XEP_0325(BasePlugin): """ - XEP-0325: IoT Control + XEP-0325: IoT Control - Actuators are devices in sensor networks that can be controlled through - the network and act with the outside world. In sensor networks and - Internet of Things applications, actuators make it possible to automate - real-world processes. - This plugin implements a mechanism whereby actuators can be controlled - in XMPP-based sensor networks, making it possible to integrate sensors - and actuators of different brands, makes and models into larger + Actuators are devices in sensor networks that can be controlled through + the network and act with the outside world. In sensor networks and + Internet of Things applications, actuators make it possible to automate + real-world processes. + This plugin implements a mechanism whereby actuators can be controlled + in XMPP-based sensor networks, making it possible to integrate sensors + and actuators of different brands, makes and models into larger Internet of Things applications. Also see @@ -52,9 +52,9 @@ class XEP_0325(BasePlugin): Client side ----------- - Control Event:SetResponse -- Received a response to a + Control Event:SetResponse -- Received a response to a control request, type result - Control Event:SetResponseError -- Received a response to a + Control Event:SetResponseError -- Received a response to a control request, type error Attributes: @@ -65,7 +65,7 @@ class XEP_0325(BasePlugin): relevant to a request's session. This dictionary is used both by the client and sensor side. On client side, seqnr is used as key, while on sensor side, a session_id is used - as key. This ensures that the two will not collide, so + as key. This ensures that the two will not collide, so one instance can be both client and sensor. Sensor side ----------- @@ -85,15 +85,15 @@ class XEP_0325(BasePlugin): Sensor side ----------- - register_node -- Register a sensor as available from this XMPP + register_node -- Register a sensor as available from this XMPP instance. Client side ----------- - set_request -- Initiates a control request to modify data in + set_request -- Initiates a control request to modify data in sensor(s). Non-blocking, a callback function will be called when the sensor has responded. - set_command -- Initiates a control command to modify data in + set_command -- Initiates a control command to modify data in sensor(s). Non-blocking. The sensor(s) will not respond regardless of the result of the command, so no callback is made. @@ -102,7 +102,7 @@ class XEP_0325(BasePlugin): name = 'xep_0325' description = 'XEP-0325 Internet of Things - Control' - dependencies = set(['xep_0030']) + dependencies = set(['xep_0030']) stanza = stanza @@ -170,10 +170,10 @@ class XEP_0325(BasePlugin): def register_node(self, nodeId, device, commTimeout, sourceId=None, cacheType=None): """ - Register a sensor/device as available for control requests/commands - through this XMPP instance. + Register a sensor/device as available for control requests/commands + through this XMPP instance. - The device object may by any custom implementation to support + The device object may by any custom implementation to support specific devices, but it must implement the functions: has_control_field set_control_fields @@ -185,11 +185,11 @@ class XEP_0325(BasePlugin): commTimeout -- Time in seconds to wait between each callback from device during a data readout. Float. sourceId -- [optional] identifying the data source controlling the device - cacheType -- [optional] narrowing down the search to a specific kind of node + cacheType -- [optional] narrowing down the search to a specific kind of node """ - self.nodes[nodeId] = {"device": device, + self.nodes[nodeId] = {"device": device, "commTimeout": commTimeout, - "sourceId": sourceId, + "sourceId": sourceId, "cacheType": cacheType}; def _set_authenticated(self, auth=''): @@ -205,10 +205,10 @@ class XEP_0325(BasePlugin): def _handle_set_req(self, iq): """ - Event handler for reception of an Iq with set req - this is a + Event handler for reception of an Iq with set req - this is a control request. - Verifies that + Verifies that - all the requested nodes are available (if no nodes are specified in the request, assume all nodes) - all the control fields are available from all requested nodes @@ -216,7 +216,7 @@ class XEP_0325(BasePlugin): If the request passes verification, the control request is passed to the devices (in a separate thread). - If the verification fails, a setResponse with error indication + If the verification fails, a setResponse with error indication is sent. """ @@ -279,17 +279,17 @@ class XEP_0325(BasePlugin): if missing_node is not None: iq['setResponse'].add_node(missing_node); if missing_field is not None: - iq['setResponse'].add_data(missing_field); + iq['setResponse'].add_data(missing_field); iq['setResponse']['error']['var'] = "Output"; iq['setResponse']['error']['text'] = error_msg; - iq.send(block=False); + iq.send(block=False); def _handle_direct_set(self, msg): """ - Event handler for reception of a Message with set command - this is a + Event handler for reception of a Message with set command - this is a direct control command. - Verifies that + Verifies that - all the requested nodes are available (if no nodes are specified in the request, assume all nodes) - all the control fields are available from all requested nodes @@ -342,9 +342,9 @@ class XEP_0325(BasePlugin): def _threaded_node_request(self, session, process_fields): - """ + """ Helper function to handle the device control in a separate thread. - + Arguments: session -- The request session id process_fields -- The fields to set in the devices. List of tuple format: @@ -360,12 +360,12 @@ class XEP_0325(BasePlugin): self.nodes[node]['device'].set_control_fields(process_fields, session=session, callback=self._device_set_command_callback); def _event_comm_timeout(self, session, nodeId): - """ + """ Triggered if any of the control operations timeout. Stop communicating with the failing device. - If the control command was an Iq request, sends a failure - message back to the client. - + If the control command was an Iq request, sends a failure + message back to the client. + Arguments: session -- The request session id nodeId -- The id of the device which timed out @@ -380,7 +380,7 @@ class XEP_0325(BasePlugin): iq['id'] = self.sessions[session]['seqnr']; iq['setResponse']['responseCode'] = "OtherError"; iq['setResponse'].add_node(nodeId); - iq['setResponse']['error']['var'] = "Output"; + iq['setResponse']['error']['var'] = "Output"; iq['setResponse']['error']['text'] = "Timeout."; iq.send(block=False); @@ -393,9 +393,9 @@ class XEP_0325(BasePlugin): del self.sessions[session]; def _all_nodes_done(self, session): - """ + """ Checks wheter all devices are done replying to the control command. - + Arguments: session -- The request session id """ @@ -405,19 +405,19 @@ class XEP_0325(BasePlugin): return True; def _device_set_command_callback(self, session, nodeId, result, error_field=None, error_msg=None): - """ - Callback function called by the devices when the control command is + """ + Callback function called by the devices when the control command is complete or failed. - If needed, composes a message with the result and sends it back to the + If needed, composes a message with the result and sends it back to the client. - + Arguments: session -- The request session id nodeId -- The device id which initiated the callback result -- The current result status of the control command. Valid values are: "error" - Set fields failed. "ok" - All fields were set. - error_field -- [optional] Only applies when result == "error" + error_field -- [optional] Only applies when result == "error" The field name that failed (usually means it is missing) error_msg -- [optional] Only applies when result == "error". Error details when a request failed. @@ -441,12 +441,12 @@ class XEP_0325(BasePlugin): iq['setResponse'].add_node(nodeId); if error_field is not None: iq['setResponse'].add_data(error_field); - iq['setResponse']['error']['var'] = error_field; + iq['setResponse']['error']['var'] = error_field; iq['setResponse']['error']['text'] = error_msg; iq.send(block=False); # Drop communication with this device and check if we are done - self.sessions[session]["nodeDone"][nodeId] = True; + self.sessions[session]["nodeDone"][nodeId] = True; if (self._all_nodes_done(session)): # The session is complete, delete it del self.sessions[session]; @@ -473,17 +473,17 @@ class XEP_0325(BasePlugin): # Client side (data controller) API def set_request(self, from_jid, to_jid, callback, fields, nodeIds=None): - """ + """ Called on the client side to initiade a control request. Composes a message with the request and sends it to the device(s). - Does not block, the callback will be called when the device(s) + Does not block, the callback will be called when the device(s) has responded. - + 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 availble. + The callback function must support the following arguments: from_jid -- The jid of the responding device(s) @@ -494,20 +494,20 @@ class XEP_0325(BasePlugin): "Locked" - Field(s) is locked and cannot be changed at the moment. "NotImplemented" - Request feature not implemented. - "FormError" - Error while setting with + "FormError" - Error while setting with a form (not implemented). - "OtherError" - Indicates other types of - errors, such as timeout. + "OtherError" - Indicates other types of + errors, such as timeout. Details in the error_msg. - - nodeId -- [optional] Only applicable when result == "error" - List of node Ids of failing device(s). - fields -- [optional] Only applicable when result == "error" + nodeId -- [optional] Only applicable when result == "error" + List of node Ids of failing device(s). + + fields -- [optional] Only applicable when result == "error" List of fields that failed.[optional] Mandatory when result == "rejected" or "failure". - - error_msg -- Details about why the request failed. + + error_msg -- Details about why the request failed. fields -- Fields to set. List of tuple format: (name, typename, value). nodeIds -- [optional] Limits the request to the node Ids in this list. @@ -526,14 +526,14 @@ class XEP_0325(BasePlugin): iq['set'].add_data(name=name, typename=typename, value=value); self.sessions[seqnr] = {"from": iq['from'], "to": iq['to'], "callback": callback}; - iq.send(block=False); + iq.send(block=False); def set_command(self, from_jid, to_jid, fields, nodeIds=None): - """ + """ Called on the client side to initiade a control command. Composes a message with the set commandand sends it to the device(s). Does not block. Device(s) will not respond, regardless of result. - + Arguments: from_jid -- The jid of the requester to_jid -- The jid of the device(s) @@ -553,7 +553,7 @@ class XEP_0325(BasePlugin): msg['set'].add_data(name, typename, value); # We won't get any reply, so don't create a session - msg.send(); + msg.send(); def _handle_set_response(self, iq): """ Received response from device(s) """ @@ -571,4 +571,4 @@ class XEP_0325(BasePlugin): callback = self.sessions[seqnr]["callback"]; callback(from_jid=from_jid, result=result, nodeIds=nodeIds, fields=fields, error_msg=error_msg); - + diff --git a/slixmpp/plugins/xep_0325/device.py b/slixmpp/plugins/xep_0325/device.py index 26ebc89f..642e6a62 100644 --- a/slixmpp/plugins/xep_0325/device.py +++ b/slixmpp/plugins/xep_0325/device.py @@ -13,8 +13,8 @@ import datetime class Device(object): """ Example implementation of a device control object. - - The device object may by any custom implementation to support + + The device object may by any custom implementation to support specific devices, but it must implement the functions: has_control_field set_control_fields @@ -30,7 +30,7 @@ class Device(object): and the type matches for control in this device. Arguments: - field -- The field name + field -- The field name typename -- The expected type """ if field in self.control_fields and self.control_fields[field]["type"] == typename: @@ -43,22 +43,22 @@ class Device(object): sets the data and (if needed) and calls the callback. Arguments: - fields -- List of control fields in tuple format: + fields -- List of control fields in tuple format: (name, typename, value) session -- Session id, only used in the callback as identifier callback -- Callback function to call when control set is complete. The callback function must support the following arguments: - session -- Session id, as supplied in the + session -- Session id, as supplied in the request_fields call nodeId -- Identifier for this device - result -- The current result status of the readout. + result -- The current result status of the readout. Valid values are: "error" - Set fields failed. "ok" - All fields were set. - error_field -- [optional] Only applies when result == "error" - The field name that failed + error_field -- [optional] Only applies when result == "error" + The field name that failed (usually means it is missing) error_msg -- [optional] Only applies when result == "error". Error details when a request failed. @@ -82,9 +82,9 @@ class Device(object): Sends a reject to the caller Arguments: - session -- Session id, see definition in + session -- Session id, see definition in set_control_fields function - callback -- Callback function, see definition in + callback -- Callback function, see definition in set_control_fields function """ callback(session, result="error", nodeId=self.nodeId, error_field=field, error_msg=message); @@ -95,8 +95,8 @@ class Device(object): Arguments: name -- Name of the field - typename -- Type of the field, one of: - (boolean, color, string, date, dateTime, + typename -- Type of the field, one of: + (boolean, color, string, date, dateTime, double, duration, int, long, time) value -- Field value """ diff --git a/slixmpp/plugins/xep_0325/stanza/control.py b/slixmpp/plugins/xep_0325/stanza/control.py index d3d6a257..ea0deac1 100644 --- a/slixmpp/plugins/xep_0325/stanza/control.py +++ b/slixmpp/plugins/xep_0325/stanza/control.py @@ -53,7 +53,7 @@ class ControlSet(ElementBase): Arguments: nodeId -- The ID for the node. sourceId -- [optional] identifying the data source controlling the device - cacheType -- [optional] narrowing down the search to a specific kind of node + cacheType -- [optional] narrowing down the search to a specific kind of node """ if nodeId not in self._nodes: self._nodes.add((nodeId)) @@ -117,12 +117,12 @@ class ControlSet(ElementBase): def add_data(self, name, typename, value): """ - Add a new data element. + Add a new data element. Arguments: name -- The name of the data element - typename -- The type of data element - (boolean, color, string, date, dateTime, + typename -- The type of data element + (boolean, color, string, date, dateTime, double, duration, int, long, time) value -- The value of the data element """ @@ -244,7 +244,7 @@ class ControlSetResponse(ElementBase): Arguments: nodeId -- The ID for the node. sourceId -- [optional] identifying the data source controlling the device - cacheType -- [optional] narrowing down the search to a specific kind of node + cacheType -- [optional] narrowing down the search to a specific kind of node """ if nodeId not in self._nodes: self._nodes.add(nodeId) @@ -308,7 +308,7 @@ class ControlSetResponse(ElementBase): def add_data(self, name): """ - Add a new ResponseParameter element. + Add a new ResponseParameter element. Arguments: name -- Name of the parameter @@ -389,12 +389,12 @@ class Error(ElementBase): def del_text(self): """Remove the contents inside the XML tag.""" self.xml.text = "" - return self + return self class ResponseParameter(ElementBase): - """ - Parameter element in ControlSetResponse. - """ + """ + Parameter element in ControlSetResponse. + """ namespace = 'urn:xmpp:iot:control' name = 'parameter' plugin_attrib = name @@ -402,7 +402,7 @@ class ResponseParameter(ElementBase): class BaseParameter(ElementBase): - """ + """ Parameter element in SetCommand. This is a base class, all instances of parameters added to SetCommand must be of types: BooleanParameter @@ -415,7 +415,7 @@ class BaseParameter(ElementBase): IntParameter LongParameter TimeParameter - """ + """ namespace = 'urn:xmpp:iot:control' name = 'baseParameter' plugin_attrib = name @@ -425,80 +425,80 @@ class BaseParameter(ElementBase): return self.name; class BooleanParameter(BaseParameter): - """ - Field data of type boolean. - Note that the value is expressed as a string. + """ + Field data of type boolean. + Note that the value is expressed as a string. """ name = 'boolean' plugin_attrib = name class ColorParameter(BaseParameter): - """ - Field data of type color. - Note that the value is expressed as a string. + """ + Field data of type color. + Note that the value is expressed as a string. """ name = 'color' plugin_attrib = name class StringParameter(BaseParameter): - """ - Field data of type string. + """ + Field data of type string. """ name = 'string' plugin_attrib = name class DateParameter(BaseParameter): - """ - Field data of type date. - Note that the value is expressed as a string. + """ + Field data of type date. + Note that the value is expressed as a string. """ name = 'date' plugin_attrib = name class DateTimeParameter(BaseParameter): - """ - Field data of type dateTime. - Note that the value is expressed as a string. + """ + Field data of type dateTime. + Note that the value is expressed as a string. """ name = 'dateTime' plugin_attrib = name class DoubleParameter(BaseParameter): - """ - Field data of type double. - Note that the value is expressed as a string. + """ + Field data of type double. + Note that the value is expressed as a string. """ name = 'double' plugin_attrib = name class DurationParameter(BaseParameter): - """ - Field data of type duration. - Note that the value is expressed as a string. + """ + Field data of type duration. + Note that the value is expressed as a string. """ name = 'duration' plugin_attrib = name class IntParameter(BaseParameter): - """ - Field data of type int. - Note that the value is expressed as a string. + """ + Field data of type int. + Note that the value is expressed as a string. """ name = 'int' plugin_attrib = name class LongParameter(BaseParameter): - """ - Field data of type long (64-bit int). - Note that the value is expressed as a string. + """ + Field data of type long (64-bit int). + Note that the value is expressed as a string. """ name = 'long' plugin_attrib = name class TimeParameter(BaseParameter): - """ - Field data of type time. - Note that the value is expressed as a string. + """ + Field data of type time. + Note that the value is expressed as a string. """ name = 'time' plugin_attrib = name diff --git a/slixmpp/xmlstream/resolver.py b/slixmpp/xmlstream/resolver.py index ed899569..d7fe1ea6 100644 --- a/slixmpp/xmlstream/resolver.py +++ b/slixmpp/xmlstream/resolver.py @@ -133,7 +133,7 @@ def resolve(host, port=None, service=None, proto='tcp', if not service: hosts = [(host, port)] else: - hosts = get_SRV(host, port, service, proto, + hosts = get_SRV(host, port, service, proto, resolver=resolver, use_dnspython=use_dnspython) @@ -144,7 +144,7 @@ def resolve(host, port=None, service=None, proto='tcp', results.append((host, '::1', port)) results.append((host, '127.0.0.1', port)) if use_ipv6: - for address in get_AAAA(host, resolver=resolver, + for address in get_AAAA(host, resolver=resolver, use_dnspython=use_dnspython): results.append((host, address, port)) for address in get_A(host, resolver=resolver, diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 510ae7d7..ee6d44c0 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -77,7 +77,7 @@ class TestPlugins(unittest.TestCase): p.disable('a') self.assertEqual(len(p), 0, "Wrong number of enabled plugins.") - self.assertEqual(events, ['init', 'end'], + self.assertEqual(events, ['init', 'end'], "Plugin lifecycle methods not called.") def test_enable_dependencies(self): diff --git a/tests/test_stanza_xep_0323.py b/tests/test_stanza_xep_0323.py index 405245b5..95fb138b 100644 --- a/tests/test_stanza_xep_0323.py +++ b/tests/test_stanza_xep_0323.py @@ -6,7 +6,7 @@ import slixmpp.plugins.xep_0323 as xep_0323 namespace='sn' class TestSensorDataStanzas(SlixTest): - + def setUp(self): pass @@ -171,7 +171,7 @@ class TestSensorDataStanzas(SlixTest): iq['accepted']['seqnr'] = '2' self.check(iq,""" - @@ -193,7 +193,7 @@ class TestSensorDataStanzas(SlixTest): iq['rejected']['error'] = 'Access denied.' self.check(iq,""" - @@ -250,7 +250,7 @@ class TestSensorDataStanzas(SlixTest): - + @@ -269,7 +269,7 @@ class TestSensorDataStanzas(SlixTest): - + @@ -314,7 +314,7 @@ class TestSensorDataStanzas(SlixTest): - + @@ -323,18 +323,18 @@ class TestSensorDataStanzas(SlixTest): - - - - - - - - - - - - + + + + + + + + + + + + @@ -342,7 +342,7 @@ class TestSensorDataStanzas(SlixTest): """ ) - + def testTimestamp(self): msg = self.Message(); @@ -386,8 +386,8 @@ class TestSensorDataStanzas(SlixTest): self.check(msg,emptyStringIdXML) msg['fields']['stringIds'] = "1" self.check(msg,emptyStringIdXML) - - + + suite = unittest.TestLoader().loadTestsFromTestCase(TestSensorDataStanzas) diff --git a/tests/test_stanza_xep_0325.py b/tests/test_stanza_xep_0325.py index 222e10ea..75a45907 100644 --- a/tests/test_stanza_xep_0325.py +++ b/tests/test_stanza_xep_0325.py @@ -15,7 +15,7 @@ import slixmpp.plugins.xep_0325 as xep_0325 namespace='sn' class TestControlStanzas(SlixTest): - + def setUp(self): pass @@ -89,7 +89,7 @@ class TestControlStanzas(SlixTest): msg['set'].add_data("Tjohej", "boolean", "true") self.check(msg,""" - @@ -244,5 +244,5 @@ class TestControlStanzas(SlixTest): """ ) - + suite = unittest.TestLoader().loadTestsFromTestCase(TestControlStanzas) diff --git a/tests/test_stream_xep_0323.py b/tests/test_stream_xep_0323.py index 3f54d861..d8e3b01f 100644 --- a/tests/test_stream_xep_0323.py +++ b/tests/test_stream_xep_0323.py @@ -46,7 +46,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -60,11 +60,11 @@ class TestStreamSensorData(SlixTest): - + - + """) def testRequestRejectAuth(self): @@ -85,7 +85,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -118,7 +118,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -142,7 +142,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -177,7 +177,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -201,7 +201,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -215,11 +215,11 @@ class TestStreamSensorData(SlixTest): - + - + """) self.send(""" @@ -227,7 +227,7 @@ class TestStreamSensorData(SlixTest): to='master@clayster.com/amr'> - + """) def testRequestMultiTimestampSingleField(self): @@ -260,7 +260,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -274,11 +274,11 @@ class TestStreamSensorData(SlixTest): - + - + """) self.send(""" @@ -287,11 +287,11 @@ class TestStreamSensorData(SlixTest): - + - + """) self.send(""" @@ -299,7 +299,7 @@ class TestStreamSensorData(SlixTest): to='master@clayster.com/amr'> - + """) def testRequestMultiTimestampAllFields(self): @@ -330,7 +330,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -344,11 +344,11 @@ class TestStreamSensorData(SlixTest): - + - + """) self.send(""" @@ -357,12 +357,12 @@ class TestStreamSensorData(SlixTest): - - + + - + """) self.send(""" @@ -370,7 +370,7 @@ class TestStreamSensorData(SlixTest): to='master@clayster.com/amr'> - + """) def testRequestAPI(self): @@ -424,7 +424,7 @@ 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"): @@ -445,19 +445,19 @@ class TestStreamSensorData(SlixTest): """) self.recv(""" - Invalid device Device22 - + """) time.sleep(.1) - self.failUnless(results == ["rejected"], + self.failUnless(results == ["rejected"], "Rejected callback was not properly executed"); def testRequestAcceptedAPI(self): @@ -466,7 +466,7 @@ 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); @@ -486,17 +486,17 @@ class TestStreamSensorData(SlixTest): """) self.recv(""" - - + """) time.sleep(.1) - self.failUnless(results == ["accepted"], + self.failUnless(results == ["accepted"], "Accepted callback was not properly executed"); def testRequestFieldsAPI(self): @@ -505,8 +505,8 @@ 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); @@ -519,9 +519,9 @@ class TestStreamSensorData(SlixTest): t1= threading.Thread(name="request_data", target=self.xmpp['xep_0323'].request_data, - kwargs={"from_jid": "tester@localhost", - "to_jid": "you@google.com", - "nodeIds": ['Device33'], + kwargs={"from_jid": "tester@localhost", + "to_jid": "you@google.com", + "nodeIds": ['Device33'], "callback": my_callback}); t1.start(); #self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback); @@ -538,12 +538,12 @@ class TestStreamSensorData(SlixTest): """) self.recv(""" - - + """) self.recv(""" @@ -552,19 +552,19 @@ class TestStreamSensorData(SlixTest): - - + + - + """) self.recv(""" - + """) t1.join(); @@ -605,8 +605,8 @@ class TestStreamSensorData(SlixTest): - - +
+ """) def testServiceDiscoveryComponent(self): @@ -631,8 +631,8 @@ class TestStreamSensorData(SlixTest): - - + + """) def testRequestTimeout(self): @@ -642,7 +642,7 @@ class TestStreamSensorData(SlixTest): 'xep_0323']) results = []; - callback_data = {}; + callback_data = {}; def my_callback(from_jid, result, nodeId=None, timestamp=None, error_msg=None): results.append(result); @@ -653,9 +653,9 @@ class TestStreamSensorData(SlixTest): t1= threading.Thread(name="request_data", target=self.xmpp['xep_0323'].request_data, - kwargs={"from_jid": "tester@localhost", - "to_jid": "you@google.com", - "nodeIds": ['Device33'], + kwargs={"from_jid": "tester@localhost", + "to_jid": "you@google.com", + "nodeIds": ['Device33'], "callback": my_callback}); t1.start(); @@ -671,12 +671,12 @@ class TestStreamSensorData(SlixTest): """) self.recv(""" - - + """) self.recv(""" @@ -729,7 +729,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -743,7 +743,7 @@ class TestStreamSensorData(SlixTest): - + """) self.send(""" @@ -752,11 +752,11 @@ class TestStreamSensorData(SlixTest): - + - + """) def testDelayedRequestFail(self): @@ -792,7 +792,7 @@ class TestStreamSensorData(SlixTest): xml_stanza['rejected']['error'] = error_text self._filtered_stanza_check(""" - @@ -847,7 +847,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -861,11 +861,11 @@ class TestStreamSensorData(SlixTest): - + - + """) self.send(""" @@ -874,11 +874,11 @@ class TestStreamSensorData(SlixTest): - + - + """) self.send(""" @@ -886,7 +886,7 @@ class TestStreamSensorData(SlixTest): to='master@clayster.com/amr'> - + """) def testRequestFieldTo(self): @@ -917,7 +917,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -931,11 +931,11 @@ class TestStreamSensorData(SlixTest): - + - + """) self.send(""" @@ -944,11 +944,11 @@ class TestStreamSensorData(SlixTest): - + - + """) self.send(""" @@ -956,7 +956,7 @@ class TestStreamSensorData(SlixTest): to='master@clayster.com/amr'> - + """) def testRequestFieldFromTo(self): @@ -987,7 +987,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - @@ -1001,11 +1001,11 @@ class TestStreamSensorData(SlixTest): - + - + """) self.send(""" @@ -1013,7 +1013,7 @@ class TestStreamSensorData(SlixTest): to='master@clayster.com/amr'> - + """) def testDelayedRequestClient(self): @@ -1021,8 +1021,8 @@ 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); @@ -1035,9 +1035,9 @@ class TestStreamSensorData(SlixTest): t1= threading.Thread(name="request_data", target=self.xmpp['xep_0323'].request_data, - kwargs={"from_jid": "tester@localhost", - "to_jid": "you@google.com", - "nodeIds": ['Device33'], + kwargs={"from_jid": "tester@localhost", + "to_jid": "you@google.com", + "nodeIds": ['Device33'], "callback": my_callback}); t1.start(); #self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback); @@ -1054,20 +1054,20 @@ class TestStreamSensorData(SlixTest): """) self.recv(""" - - + """) self.recv(""" - - """) + + """) self.recv(""" - - + + - + """) self.recv(""" - + """) t1.join(); @@ -1114,7 +1114,7 @@ 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); @@ -1133,12 +1133,12 @@ class TestStreamSensorData(SlixTest): """) self.recv(""" - - + """) self.xmpp['xep_0323'].cancel_request(session=session); @@ -1192,7 +1192,7 @@ class TestStreamSensorData(SlixTest): """) self.send(""" - diff --git a/tests/test_stream_xep_0325.py b/tests/test_stream_xep_0325.py index b85342ff..0d4ab907 100644 --- a/tests/test_stream_xep_0325.py +++ b/tests/test_stream_xep_0325.py @@ -60,7 +60,7 @@ class TestStreamControl(SlixTest): to='master@clayster.com/amr' id='1'> - + """) self.assertEqual(myDevice._get_field_value("Temperature"), "17"); @@ -99,7 +99,7 @@ class TestStreamControl(SlixTest): to='master@clayster.com/amr' id='1'> - + """) self.assertEqual(myDevice._get_field_value("Temperature"), "17"); @@ -125,7 +125,7 @@ class TestStreamControl(SlixTest): to='master@clayster.com/amr' id='2'> - + """) self.assertEqual(myDevice._get_field_value("Temperature"), "20"); @@ -163,7 +163,7 @@ class TestStreamControl(SlixTest): Invalid field Voltage - + """) self.assertEqual(myDevice._get_field_value("Temperature"), "15"); @@ -180,7 +180,7 @@ class TestStreamControl(SlixTest): self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5); self.recv(""" - @@ -204,7 +204,7 @@ class TestStreamControl(SlixTest): self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5); self.recv(""" - @@ -225,7 +225,7 @@ 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); @@ -256,7 +256,7 @@ class TestStreamControl(SlixTest): to='tester@localhost' id='1'> - + """) time.sleep(.5) @@ -269,7 +269,7 @@ 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); @@ -302,7 +302,7 @@ class TestStreamControl(SlixTest): Sensor error - + """) time.sleep(.5) @@ -330,8 +330,8 @@ class TestStreamControl(SlixTest): - - + + """) def testServiceDiscoveryComponent(self): @@ -356,8 +356,8 @@ class TestStreamControl(SlixTest): - - + + """) -- cgit v1.2.3