New plugin configuration options:
use_cache - Enable caching disco info results. Defaults to True
wrap_results - Always return disco results in an Iq stanza. Defaults
to False
Node handler changes:
Handlers now take four arguments: jid, node, ifrom, data
Most older style handlers will still work, depending on if they
raise a TypeError for incorrect number of arguments. Handlers that
used *args may not work.
New get_info options:
cached - Passing cached=True to get_info() will attempt to load
results from the cache. If nothing is found, a query
will be sent as normal. If set to False, the cache
will be skipped, even if it contains results.
New method:
supports() - Given a JID/node pair and a feature, return True
if the feature is supported, False if not, and
None if there was a timeout. By default, the search
will use the cache.
Updated the XML-RPC value conversion to correctly apply namespaces, and
fixed an error uncovered by the tests in the XML -> Python conversion of
dateTime values.
This allows applications to filter out sensitive information, such
as passwords, so that it won't appear in the logs.
It does mean that the debug logs will not show the actual received
data, and there will be no indication of tampering, unless the
filter author explicitly logs and notes that a change was made.
A filter accepts and returns a stanza, but potentially modified.
To prevent sending/receiving a stanza, a filter may return None.
Incoming:
self.add_filter('in', in_filter)
Outgoing:
self.add_filter('out', out_filter)
Filters are applied in the order thay are added. However, you may
add an order parameter, which is the place in the list to insert the
filter:
self.add_filter('in', in_filter, order=0)
Only allowing handlers to return a DiscoInfo/DiscoItem stanza works
for the majority of cases, but does not allow for the addition of
an RSM stanza, or other extensions.
An Iq stanza returned by a handler must already be configured as
a reply.
May set self.disconnect_wait=True so that all disconnect
calls wait for the send queue to empty, unless explicitly
overridden with wait=False.
The session_end now fires before closing the socket so
that final stanzas may be sent, such as unavailable presences
for components.
The form plugin was being registered on first use for providers,
but not for clients receiving the form.
NOTE: Use of non-form payloads will have this issue - adhoc command
clients will need to have an expectation beforehand of what
the command payload will be to properly load stanza plugins.
Calling reconnect() simultaneously from multiple threads (like when
using XEP-0199 keepalive) could break because the connection state
can transition and break the state expectations in one of the
reconnect() calls.
Note that using % in a string will _always_ perform the sting substitutions, because the strings are constructed before the function is called. So log.debug('%s' % expensiveoperation()) will take about the same CPU time whether or not the logging level is DEBUG or INFO. if you use , no substitutions are performed unless the string is actually logged
Note that using % in a string will _always_ perform the sting substitutions, because the strings are constructed before the function is called. So log.debug('%s' % expensiveoperation()) will take about the same CPU time whether or not the logging level is DEBUG or INFO. if you use , no substitutions are performed unless the string is actually logged
The change to using the new roster broke the original auto_* values
and used per-roster versions. The original auto_* values will now set
the behaviour globally. Use the per-roster values to override for a
specific JID.
The mechanism name was being correctly de-plussed, but then we used the
original, -PLUS, name to extract the hash, finding SHA-1-PLUS and therefore
finding no match.
Test-Information:
Tested with Sleek against an Isode M-Link with SCRAM-SHA-1-PLUS available.
Author: dwd
Instead of using:
ClientXMPP(jid, password, plugin_config={
'feature_mechanisms': {'use_mech': 'SOME-MECH'}})
You can use:
ClientXMPP(jid, password, sasl_mech='SOME-MECH')
If you need to change the mechanism after instantiation, use:
xmpp['feature_mechanisms'].sasl.mech = 'SCRAM-MD5'
The processing loop was continuing to call __read_xml after </stream>
was received, which caused SyntaxErrors (can't find starting element).
This should fix issue #102
May be disabled by setting:
self.whitespace_keepalive = False
The keepalive interval can be adjusted using:
self.whitespace_keepalive_interval = 300
The default interval is 5min.
Fixes:
README.rst now included
Double line spacing removed from long_description
Source package now includes tests, examples, etc using Manifest.in
README.rst typos fixed
Added README.rst section on installing dnspython for Python3
Version bumped to RC2
Version is now taken from sleekxmpp.version.__version__ without
having to pull in the entire library
Added 'test' command for setup.py
Simplified testall.py
Docs build cleanly from source package after installation
IqError and IqTimeout now extend XMPPError, so if you don't care
about the difference, you can use:
try:
self.do_something_with_iqs()
except XMPPError:
# Error? Timeout? I don't care!
pass
If you do need to distinguish between timeouts and error replies,
you can still continue to use:
try:
self.do_somethin_with_iqs()
except IqError as err:
pass
except IqTimeout:
pass
If you don't catch any Iq errors and you're processing a stanza
then an error response will be sent, just like normal if you raise
XMPPError or any other exception, except that the error messages
will be generic to prevent leaking too much information.
Can now use len(self.client_roster) to get the number of JIDs in
the roster, and self.client_roster.groups() to get a dict of
groups and the JIDs in those groups.
Form fields now remember their current type if the type is deleted. This
allows for fields to properly format their values if set after the form
has been changed to the 'submit' type.
IqError is now caught and forwarded to the command error handler referenced
in the session.
Errors are now caught and processed by the session's error handler
whether or not the results Iq stanza includes the <command> substanza.
Added the option for blocking command calls. The blocking option is set
during start_command with block=True. Subsequent command flow methods use
session['block'] to determine their blocking behaviour.
If you use blocking commands, then you will need to wrap your command calls
in a try/except block for IqTimeout exceptions.
Changes:
May now use underscored method names
form.field is replaced by form['fields']
form.get_fields no longer accepts use_dict parameter, it always
returns an OrderedDict now
form.set_fields will accept either an OrderedDict, or a list
of (var, dict) tuples as before.
Setting the form type to 'submit' will remove extra meta data
from the form fields, leaving just the 'var' and 'value'
Setting the form type to 'cancel' will remove all fields.
Honestly, this is mainly just a demo/proof of concept that we
can handle dependencies and ordering issues with stream features.
DON'T use XEP-0078 if you are able to use the normal SASL method,
which should be the case unless you are dealing with a very old
XMPP server implementation.
Sleek loads a few plugins by default, which made it difficult to
configure or even disable them.
Now, if a plugin is registered without any configuration, then
sleek will try finding a configuration in self.plugin_config.
Thus, using the XEP-0082 and XEP-0202 introduces a dependency
on the dateutil package (installable using pip install python-dateutil).
Maybe we'll be able to rework how these plugins work to avoid
needing dateutil, but for now this will have to do.
Accepting download requests can be done using:
self['xep_0066'].register_url_handler(handler=self.oob_download)
# Add jid=... to specify a handler for a particular JID for a
# componenent.
def oob_download(self, iq):
if iq['from'] not in self.custom_oob_whitelist:
raise XMPPError('not-authorized')
try:
data = urllib2.urlopen(iq['oob_transfer']['url'])
file = open('oob_download', 'w+')
file.write(data.read())
file.close()
data.close()
except:
raise XMPPError('item-not-found')
If wait=True, then the disconnect call will block until
the send queue has emptied.
WARNING: Using wait=True when more stanzas are being added to the
queue than can be processed such that the queue is never empty
will cause the disconnect call to block indefinitely without actually
disconnecting.