PEP8 formatting updates.

This commit is contained in:
Lance Stout 2012-06-19 01:29:48 -07:00
parent f7a74d960e
commit d92aa05b5c
58 changed files with 324 additions and 289 deletions

View File

@ -16,24 +16,24 @@ class APIWrapper(object):
elif attr == 'settings': elif attr == 'settings':
return self.api.settings[self.name] return self.api.settings[self.name]
elif attr == 'register': elif attr == 'register':
def curried_handler(handler, op, jid=None, node=None, default=False): def partial(handler, op, jid=None, node=None, default=False):
register = getattr(self.api, attr) register = getattr(self.api, attr)
return register(handler, self.name, op, jid, node, default) return register(handler, self.name, op, jid, node, default)
return curried_handler return partial
elif attr == 'register_default': elif attr == 'register_default':
def curried_handler(handler, op, jid=None, node=None): def partial(handler, op, jid=None, node=None):
return getattr(self.api, attr)(handler, self.name, op) return getattr(self.api, attr)(handler, self.name, op)
return curried_handler return partial
elif attr in ('run', 'restore_default', 'unregister'): elif attr in ('run', 'restore_default', 'unregister'):
def curried_handler(*args, **kwargs): def partial(*args, **kwargs):
return getattr(self.api, attr)(self.name, *args, **kwargs) return getattr(self.api, attr)(self.name, *args, **kwargs)
return curried_handler return partial
return None return None
def __getitem__(self, attr): def __getitem__(self, attr):
def curried_handler(jid=None, node=None, ifrom=None, args=None): def partial(jid=None, node=None, ifrom=None, args=None):
return self.api.run(self.name, attr, jid, node, ifrom, args) return self.api.run(self.name, attr, jid, node, ifrom, args)
return curried_handler return partial
class APIRegistry(object): class APIRegistry(object):
@ -42,7 +42,7 @@ class APIRegistry(object):
self._handlers = {} self._handlers = {}
self._handler_defaults = {} self._handler_defaults = {}
self.xmpp = xmpp self.xmpp = xmpp
self.settings = {} self.settings = {}
def _setup(self, ctype, op): def _setup(self, ctype, op):
"""Initialize the API callback dictionaries. """Initialize the API callback dictionaries.
@ -138,8 +138,8 @@ class APIRegistry(object):
"""Register an API callback, with JID+node specificity. """Register an API callback, with JID+node specificity.
The API callback can later be executed based on the The API callback can later be executed based on the
specificity of the provided JID+node combination. specificity of the provided JID+node combination.
See :meth:`~ApiRegistry.run` for more details. See :meth:`~ApiRegistry.run` for more details.
:param string ctype: The name of the API to use. :param string ctype: The name of the API to use.

View File

@ -67,7 +67,7 @@ class BaseXMPP(XMLStream):
#: An identifier for the stream as given by the server. #: An identifier for the stream as given by the server.
self.stream_id = None self.stream_id = None
#: The JabberID (JID) used by this connection. #: The JabberID (JID) used by this connection.
self.boundjid = JID(jid) self.boundjid = JID(jid)
self._expected_server_name = self.boundjid.host self._expected_server_name = self.boundjid.host
@ -103,7 +103,7 @@ class BaseXMPP(XMLStream):
#: The API registry is a way to process callbacks based on #: The API registry is a way to process callbacks based on
#: JID+node combinations. Each callback in the registry is #: JID+node combinations. Each callback in the registry is
#: marked with: #: marked with:
#: #:
#: - An API name, e.g. xep_0030 #: - An API name, e.g. xep_0030
#: - The name of an action, e.g. get_info #: - The name of an action, e.g. get_info
#: - The JID that will be affected #: - The JID that will be affected
@ -202,7 +202,7 @@ class BaseXMPP(XMLStream):
Defaults to ``True``. This does **not** mean that no Defaults to ``True``. This does **not** mean that no
threads are used at all if ``threaded=False``. threads are used at all if ``threaded=False``.
Regardless of these threading options, these threads will Regardless of these threading options, these threads will
always exist: always exist:
- The event queue processor - The event queue processor
@ -294,11 +294,11 @@ class BaseXMPP(XMLStream):
:param id: An ideally unique ID value for this stanza thread. :param id: An ideally unique ID value for this stanza thread.
Defaults to 0. Defaults to 0.
:param ifrom: The from :class:`~sleekxmpp.xmlstream.jid.JID` :param ifrom: The from :class:`~sleekxmpp.xmlstream.jid.JID`
to use for this stanza. to use for this stanza.
:param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID` :param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID`
for this stanza. for this stanza.
:param itype: The :class:`~sleekxmpp.stanza.iq.Iq`'s type, :param itype: The :class:`~sleekxmpp.stanza.iq.Iq`'s type,
one of: ``'get'``, ``'set'``, ``'result'``, one of: ``'get'``, ``'set'``, ``'result'``,
or ``'error'``. or ``'error'``.
:param iquery: Optional namespace for adding a query element. :param iquery: Optional namespace for adding a query element.
@ -336,7 +336,7 @@ class BaseXMPP(XMLStream):
def make_iq_result(self, id=None, ito=None, ifrom=None, iq=None): def make_iq_result(self, id=None, ito=None, ifrom=None, iq=None):
""" """
Create an :class:`~sleekxmpp.stanza.iq.Iq` stanza of type Create an :class:`~sleekxmpp.stanza.iq.Iq` stanza of type
``'result'`` with the given ID value. ``'result'`` with the given ID value.
:param id: An ideally unique ID value. May use :meth:`new_id()`. :param id: An ideally unique ID value. May use :meth:`new_id()`.
@ -366,10 +366,10 @@ class BaseXMPP(XMLStream):
Optionally, a substanza may be given to use as the Optionally, a substanza may be given to use as the
stanza's payload. stanza's payload.
:param sub: Either an :param sub: Either an
:class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase`
stanza object or an stanza object or an
:class:`~xml.etree.ElementTree.Element` XML object :class:`~xml.etree.ElementTree.Element` XML object
to use as the :class:`~sleekxmpp.stanza.iq.Iq`'s payload. to use as the :class:`~sleekxmpp.stanza.iq.Iq`'s payload.
:param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID` :param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID`
for this stanza. for this stanza.
@ -396,9 +396,9 @@ class BaseXMPP(XMLStream):
Create an :class:`~sleekxmpp.stanza.iq.Iq` stanza of type ``'error'``. Create an :class:`~sleekxmpp.stanza.iq.Iq` stanza of type ``'error'``.
:param id: An ideally unique ID value. May use :meth:`new_id()`. :param id: An ideally unique ID value. May use :meth:`new_id()`.
:param type: The type of the error, such as ``'cancel'`` or :param type: The type of the error, such as ``'cancel'`` or
``'modify'``. Defaults to ``'cancel'``. ``'modify'``. Defaults to ``'cancel'``.
:param condition: The error condition. Defaults to :param condition: The error condition. Defaults to
``'feature-not-implemented'``. ``'feature-not-implemented'``.
:param text: A message describing the cause of the error. :param text: A message describing the cause of the error.
:param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID` :param ito: The destination :class:`~sleekxmpp.xmlstream.jid.JID`
@ -422,7 +422,7 @@ class BaseXMPP(XMLStream):
def make_iq_query(self, iq=None, xmlns='', ito=None, ifrom=None): def make_iq_query(self, iq=None, xmlns='', ito=None, ifrom=None):
""" """
Create or modify an :class:`~sleekxmpp.stanza.iq.Iq` stanza Create or modify an :class:`~sleekxmpp.stanza.iq.Iq` stanza
to use the given query namespace. to use the given query namespace.
:param iq: Optionally use an existing stanza instead :param iq: Optionally use an existing stanza instead
@ -455,7 +455,7 @@ class BaseXMPP(XMLStream):
def make_message(self, mto, mbody=None, msubject=None, mtype=None, def make_message(self, mto, mbody=None, msubject=None, mtype=None,
mhtml=None, mfrom=None, mnick=None): mhtml=None, mfrom=None, mnick=None):
""" """
Create and initialize a new Create and initialize a new
:class:`~sleekxmpp.stanza.message.Message` stanza. :class:`~sleekxmpp.stanza.message.Message` stanza.
:param mto: The recipient of the message. :param mto: The recipient of the message.
@ -481,7 +481,7 @@ class BaseXMPP(XMLStream):
def make_presence(self, pshow=None, pstatus=None, ppriority=None, def make_presence(self, pshow=None, pstatus=None, ppriority=None,
pto=None, ptype=None, pfrom=None, pnick=None): pto=None, ptype=None, pfrom=None, pnick=None):
""" """
Create and initialize a new Create and initialize a new
:class:`~sleekxmpp.stanza.presence.Presence` stanza. :class:`~sleekxmpp.stanza.presence.Presence` stanza.
:param pshow: The presence's show value. :param pshow: The presence's show value.
@ -505,7 +505,7 @@ class BaseXMPP(XMLStream):
def send_message(self, mto, mbody, msubject=None, mtype=None, def send_message(self, mto, mbody, msubject=None, mtype=None,
mhtml=None, mfrom=None, mnick=None): mhtml=None, mfrom=None, mnick=None):
""" """
Create, initialize, and send a new Create, initialize, and send a new
:class:`~sleekxmpp.stanza.message.Message` stanza. :class:`~sleekxmpp.stanza.message.Message` stanza.
:param mto: The recipient of the message. :param mto: The recipient of the message.
@ -525,7 +525,7 @@ class BaseXMPP(XMLStream):
def send_presence(self, pshow=None, pstatus=None, ppriority=None, def send_presence(self, pshow=None, pstatus=None, ppriority=None,
pto=None, pfrom=None, ptype=None, pnick=None): pto=None, pfrom=None, ptype=None, pnick=None):
""" """
Create, initialize, and send a new Create, initialize, and send a new
:class:`~sleekxmpp.stanza.presence.Presence` stanza. :class:`~sleekxmpp.stanza.presence.Presence` stanza.
:param pshow: The presence's show value. :param pshow: The presence's show value.
@ -536,13 +536,13 @@ class BaseXMPP(XMLStream):
:param pfrom: The sender of the presence. :param pfrom: The sender of the presence.
:param pnick: Optional nickname of the presence's sender. :param pnick: Optional nickname of the presence's sender.
""" """
self.make_presence(pshow, pstatus, ppriority, pto, self.make_presence(pshow, pstatus, ppriority, pto,
ptype, pfrom, pnick).send() ptype, pfrom, pnick).send()
def send_presence_subscription(self, pto, pfrom=None, def send_presence_subscription(self, pto, pfrom=None,
ptype='subscribe', pnick=None): ptype='subscribe', pnick=None):
""" """
Create, initialize, and send a new Create, initialize, and send a new
:class:`~sleekxmpp.stanza.presence.Presence` stanza of :class:`~sleekxmpp.stanza.presence.Presence` stanza of
type ``'subscribe'``. type ``'subscribe'``.
@ -743,7 +743,7 @@ class BaseXMPP(XMLStream):
return return
def exception(self, exception): def exception(self, exception):
"""Process any uncaught exceptions, notably """Process any uncaught exceptions, notably
:class:`~sleekxmpp.exceptions.IqError` and :class:`~sleekxmpp.exceptions.IqError` and
:class:`~sleekxmpp.exceptions.IqTimeout` exceptions. :class:`~sleekxmpp.exceptions.IqTimeout` exceptions.

View File

@ -54,13 +54,13 @@ class ClientXMPP(BaseXMPP):
:param password: The password for the XMPP user account. :param password: The password for the XMPP user account.
:param ssl: **Deprecated.** :param ssl: **Deprecated.**
:param plugin_config: A dictionary of plugin configurations. :param plugin_config: A dictionary of plugin configurations.
:param plugin_whitelist: A list of approved plugins that :param plugin_whitelist: A list of approved plugins that
will be loaded when calling will be loaded when calling
:meth:`~sleekxmpp.basexmpp.BaseXMPP.register_plugins()`. :meth:`~sleekxmpp.basexmpp.BaseXMPP.register_plugins()`.
:param escape_quotes: **Deprecated.** :param escape_quotes: **Deprecated.**
""" """
def __init__(self, jid, password, plugin_config={}, plugin_whitelist=[], def __init__(self, jid, password, plugin_config={}, plugin_whitelist=[],
escape_quotes=True, sasl_mech=None, lang='en'): escape_quotes=True, sasl_mech=None, lang='en'):
BaseXMPP.__init__(self, jid, 'jabber:client') BaseXMPP.__init__(self, jid, 'jabber:client')
@ -189,7 +189,7 @@ class ClientXMPP(BaseXMPP):
occurs. Defaults to ``True``. occurs. Defaults to ``True``.
:param timeout: The length of time (in seconds) to wait :param timeout: The length of time (in seconds) to wait
for a response before continuing if blocking for a response before continuing if blocking
is used. Defaults to is used. Defaults to
:attr:`~sleekxmpp.xmlstream.xmlstream.XMLStream.response_timeout`. :attr:`~sleekxmpp.xmlstream.xmlstream.XMLStream.response_timeout`.
:param callback: Optional reference to a stream handler function. :param callback: Optional reference to a stream handler function.
Will be executed when the roster is received. Will be executed when the roster is received.
@ -200,7 +200,7 @@ class ClientXMPP(BaseXMPP):
def del_roster_item(self, jid): def del_roster_item(self, jid):
"""Remove an item from the roster. """Remove an item from the roster.
This is done by setting its subscription status to ``'remove'``. This is done by setting its subscription status to ``'remove'``.
:param jid: The JID of the item to remove. :param jid: The JID of the item to remove.
@ -215,7 +215,7 @@ class ClientXMPP(BaseXMPP):
Defaults to ``True``. Defaults to ``True``.
:param timeout: The length of time (in seconds) to wait for a response :param timeout: The length of time (in seconds) to wait for a response
before continuing if blocking is used. before continuing if blocking is used.
Defaults to Defaults to
:attr:`~sleekxmpp.xmlstream.xmlstream.XMLStream.response_timeout`. :attr:`~sleekxmpp.xmlstream.xmlstream.XMLStream.response_timeout`.
:param callback: Optional reference to a stream handler function. Will :param callback: Optional reference to a stream handler function. Will
be executed when the roster is received. be executed when the roster is received.
@ -233,7 +233,7 @@ class ClientXMPP(BaseXMPP):
response = iq.send(block, timeout, callback) response = iq.send(block, timeout, callback)
self.event('roster_received', response) self.event('roster_received', response)
if block: if block:
self._handle_roster(response) self._handle_roster(response)
return response return response
@ -279,7 +279,7 @@ class ClientXMPP(BaseXMPP):
roster[jid]['pending_out'] = (item['ask'] == 'subscribe') roster[jid]['pending_out'] = (item['ask'] == 'subscribe')
roster[jid].save(remove=(item['subscription'] == 'remove')) roster[jid].save(remove=(item['subscription'] == 'remove'))
self.event("roster_update", iq) self.event("roster_update", iq)
if iq['type'] == 'set': if iq['type'] == 'set':
resp = self.Iq(stype='result', resp = self.Iq(stype='result',

View File

@ -40,8 +40,8 @@ class ComponentXMPP(BaseXMPP):
:param host: The server accepting the component. :param host: The server accepting the component.
:param port: The port used to connect to the server. :param port: The port used to connect to the server.
:param plugin_config: A dictionary of plugin configurations. :param plugin_config: A dictionary of plugin configurations.
:param plugin_whitelist: A list of approved plugins that :param plugin_whitelist: A list of approved plugins that
will be loaded when calling will be loaded when calling
:meth:`~sleekxmpp.basexmpp.BaseXMPP.register_plugins()`. :meth:`~sleekxmpp.basexmpp.BaseXMPP.register_plugins()`.
:param use_jc_ns: Indicates if the ``'jabber:client'`` namespace :param use_jc_ns: Indicates if the ``'jabber:client'`` namespace
should be used instead of the standard should be used instead of the standard
@ -78,7 +78,7 @@ class ComponentXMPP(BaseXMPP):
self.add_event_handler('presence_probe', self.add_event_handler('presence_probe',
self._handle_probe) self._handle_probe)
def connect(self, host=None, port=None, use_ssl=False, def connect(self, host=None, port=None, use_ssl=False,
use_tls=False, reattempt=True): use_tls=False, reattempt=True):
"""Connect to the server. """Connect to the server.

View File

@ -69,10 +69,11 @@ class IqTimeout(XMPPError):
condition='remote-server-timeout', condition='remote-server-timeout',
etype='cancel') etype='cancel')
#: The :class:`~sleekxmpp.stanza.iq.Iq` stanza whose response #: The :class:`~sleekxmpp.stanza.iq.Iq` stanza whose response
#: did not arrive before the timeout expired. #: did not arrive before the timeout expired.
self.iq = iq self.iq = iq
class IqError(XMPPError): class IqError(XMPPError):
""" """

View File

@ -7,9 +7,9 @@
""" """
__all__ = [ __all__ = [
'feature_starttls', 'feature_starttls',
'feature_mechanisms', 'feature_mechanisms',
'feature_bind', 'feature_bind',
'feature_session', 'feature_session',
'feature_rosterver' 'feature_rosterver'
] ]

View File

@ -23,7 +23,7 @@ class Auth(StanzaBase):
interfaces = set(('mechanism', 'value')) interfaces = set(('mechanism', 'value'))
plugin_attrib = name plugin_attrib = name
#: Some SASL mechs require sending values as is, #: Some SASL mechs require sending values as is,
#: without converting base64. #: without converting base64.
plain_mechs = set(['X-MESSENGER-OAUTH2']) plain_mechs = set(['X-MESSENGER-OAUTH2'])

View File

@ -31,10 +31,10 @@ log = logging.getLogger(__name__)
PLUGIN_REGISTRY = {} PLUGIN_REGISTRY = {}
#: In order to do cascading plugin disabling, reverse dependencies #: In order to do cascading plugin disabling, reverse dependencies
#: must be tracked. #: must be tracked.
PLUGIN_DEPENDENTS = {} PLUGIN_DEPENDENTS = {}
#: Only allow one thread to manipulate the plugin registry at a time. #: Only allow one thread to manipulate the plugin registry at a time.
REGISTRY_LOCK = threading.RLock() REGISTRY_LOCK = threading.RLock()
@ -75,7 +75,7 @@ def load_plugin(name, module=None):
plugins are in packages matching their name, plugins are in packages matching their name,
even though the plugin class name does not even though the plugin class name does not
have to match. have to match.
:param str module: The name of the base module to search :param str module: The name of the base module to search
for the plugin. for the plugin.
""" """
try: try:
@ -107,7 +107,7 @@ def load_plugin(name, module=None):
log.exception("Unable to load plugin: %s", name) log.exception("Unable to load plugin: %s", name)
class PluginManager(object): class PluginManager(object):
def __init__(self, xmpp, config=None): def __init__(self, xmpp, config=None):
#: We will track all enabled plugins in a set so that we #: We will track all enabled plugins in a set so that we
#: can enable plugins in batches and pull in dependencies #: can enable plugins in batches and pull in dependencies
@ -181,7 +181,7 @@ class PluginManager(object):
def enable_all(self, names=None, config=None): def enable_all(self, names=None, config=None):
"""Enable all registered plugins. """Enable all registered plugins.
:param list names: A list of plugin names to enable. If :param list names: A list of plugin names to enable. If
none are provided, all registered plugins none are provided, all registered plugins
will be enabled. will be enabled.
@ -292,7 +292,7 @@ class BasePlugin(object):
def post_init(self): def post_init(self):
"""Initialize any cross-plugin state. """Initialize any cross-plugin state.
Only needed if the plugin has circular dependencies. Only needed if the plugin has circular dependencies.
""" """
pass pass

View File

@ -81,7 +81,8 @@ class XEP_0027(BasePlugin):
def _sign_presence(self, stanza): def _sign_presence(self, stanza):
if isinstance(stanza, Presence): if isinstance(stanza, Presence):
if stanza['type'] == 'available' or stanza['type'] in Presence.showtypes: if stanza['type'] == 'available' or \
stanza['type'] in Presence.showtypes:
stanza['signed'] = stanza['status'] stanza['signed'] = stanza['status']
return stanza return stanza

View File

@ -51,6 +51,3 @@ class Encrypted(ElementBase):
if self.xml.text: if self.xml.text:
return xmpp['xep_0027'].decrypt(self.xml.text, parent['to']) return xmpp['xep_0027'].decrypt(self.xml.text, parent['to'])
return None return None

View File

@ -339,8 +339,8 @@ class XEP_0030(BasePlugin):
if local: if local:
log.debug("Looking up local disco#info data " + \ log.debug("Looking up local disco#info data " + \
"for %s, node %s.", jid, node) "for %s, node %s.", jid, node)
info = self.api['get_info'](jid, node, info = self.api['get_info'](jid, node,
kwargs.get('ifrom', None), kwargs.get('ifrom', None),
kwargs) kwargs)
info = self._fix_default_info(info) info = self._fix_default_info(info)
return self._wrap(kwargs.get('ifrom', None), jid, info) return self._wrap(kwargs.get('ifrom', None), jid, info)
@ -348,8 +348,8 @@ class XEP_0030(BasePlugin):
if cached: if cached:
log.debug("Looking up cached disco#info data " + \ log.debug("Looking up cached disco#info data " + \
"for %s, node %s.", jid, node) "for %s, node %s.", jid, node)
info = self.api['get_cached_info'](jid, node, info = self.api['get_cached_info'](jid, node,
kwargs.get('ifrom', None), kwargs.get('ifrom', None),
kwargs) kwargs)
if info is not None: if info is not None:
return self._wrap(kwargs.get('ifrom', None), jid, info) return self._wrap(kwargs.get('ifrom', None), jid, info)
@ -405,8 +405,8 @@ class XEP_0030(BasePlugin):
Otherwise the parameter is ignored. Otherwise the parameter is ignored.
""" """
if local or jid is None: if local or jid is None:
items = self.api['get_items'](jid, node, items = self.api['get_items'](jid, node,
kwargs.get('ifrom', None), kwargs.get('ifrom', None),
kwargs) kwargs)
return self._wrap(kwargs.get('ifrom', None), jid, items) return self._wrap(kwargs.get('ifrom', None), jid, items)

View File

@ -16,7 +16,7 @@ class Addresses(ElementBase):
plugin_attrib = 'addresses' plugin_attrib = 'addresses'
interfaces = set() interfaces = set()
def add_address(self, atype='to', jid='', node='', uri='', def add_address(self, atype='to', jid='', node='', uri='',
desc='', delivered=False): desc='', delivered=False):
addr = Address(parent=self) addr = Address(parent=self)
addr['type'] = atype addr['type'] = atype
@ -116,7 +116,7 @@ for atype in ('all', 'bcc', 'cc', 'noreply', 'replyroom', 'replyto', 'to'):
setattr(Addresses, "get_%s" % atype, get_multi) setattr(Addresses, "get_%s" % atype, get_multi)
setattr(Addresses, "set_%s" % atype, set_multi) setattr(Addresses, "set_%s" % atype, set_multi)
setattr(Addresses, "del_%s" % atype, del_multi) setattr(Addresses, "del_%s" % atype, del_multi)
# To retain backwards compatibility: # To retain backwards compatibility:
setattr(Addresses, "get%s" % atype.title(), get_multi) setattr(Addresses, "get%s" % atype.title(), get_multi)
setattr(Addresses, "set%s" % atype.title(), set_multi) setattr(Addresses, "set%s" % atype.title(), set_multi)

View File

@ -106,8 +106,8 @@ class Address(ElementBase):
namespace = 'vcard-temp' namespace = 'vcard-temp'
plugin_attrib = name plugin_attrib = name
plugin_multi_attrib = 'addresses' plugin_multi_attrib = 'addresses'
interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INTL', interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INTL',
'PREF', 'POBOX', 'EXTADD', 'STREET', 'LOCALITY', 'PREF', 'POBOX', 'EXTADD', 'STREET', 'LOCALITY',
'REGION', 'PCODE', 'CTRY']) 'REGION', 'PCODE', 'CTRY'])
sub_interfaces = set(['POBOX', 'EXTADD', 'STREET', 'LOCALITY', sub_interfaces = set(['POBOX', 'EXTADD', 'STREET', 'LOCALITY',
'REGION', 'PCODE', 'CTRY']) 'REGION', 'PCODE', 'CTRY'])
@ -123,8 +123,8 @@ class Telephone(ElementBase):
'CELL', 'VIDEO', 'BBS', 'MODEM', 'ISDN', 'PCS', 'CELL', 'VIDEO', 'BBS', 'MODEM', 'ISDN', 'PCS',
'PREF', 'NUMBER']) 'PREF', 'NUMBER'])
sub_interfaces = set(['NUMBER']) sub_interfaces = set(['NUMBER'])
bool_interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER', bool_interfaces = set(['HOME', 'WORK', 'VOICE', 'FAX', 'PAGER',
'MSG', 'CELL', 'VIDEO', 'BBS', 'MODEM', 'MSG', 'CELL', 'VIDEO', 'BBS', 'MODEM',
'ISDN', 'PCS', 'PREF']) 'ISDN', 'PCS', 'PREF'])
def setup(self, xml=None): def setup(self, xml=None):
@ -145,7 +145,7 @@ class Label(ElementBase):
plugin_multi_attrib = 'labels' plugin_multi_attrib = 'labels'
interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INT', interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', 'INT',
'PREF', 'lines']) 'PREF', 'lines'])
bool_interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM', bool_interfaces = set(['HOME', 'WORK', 'POSTAL', 'PARCEL', 'DOM',
'INT', 'PREF']) 'INT', 'PREF'])
def add_line(self, value): def add_line(self, value):
@ -515,7 +515,7 @@ class TimeZone(ElementBase):
is_extension = True is_extension = True
def set_tz(self, value): def set_tz(self, value):
time = xep_0082.time(offset=value) time = xep_0082.time(offset=value)
if time[-1] == 'Z': if time[-1] == 'Z':
self.xml.text = 'Z' self.xml.text = 'Z'
else: else:

View File

@ -53,7 +53,7 @@ class XEP_0054(BasePlugin):
def make_vcard(self): def make_vcard(self):
return VCardTemp() return VCardTemp()
def get_vcard(self, jid=None, ifrom=None, local=False, cached=False, def get_vcard(self, jid=None, ifrom=None, local=False, cached=False,
block=True, callback=None, timeout=None): block=True, callback=None, timeout=None):
if self.xmpp.is_component and jid.domain == self.xmpp.boundjid.domain: if self.xmpp.is_component and jid.domain == self.xmpp.boundjid.domain:
local = True local = True
@ -84,12 +84,12 @@ class XEP_0054(BasePlugin):
iq.enable('vcard_temp') iq.enable('vcard_temp')
vcard = iq.send(block=block, callback=callback, timeout=timeout) vcard = iq.send(block=block, callback=callback, timeout=timeout)
if block: if block:
self.api['set_vcard'](vcard['from'], args=vcard['vcard_temp']) self.api['set_vcard'](vcard['from'], args=vcard['vcard_temp'])
return vcard return vcard
def publish_vcard(self, vcard=None, jid=None, block=True, ifrom=None, def publish_vcard(self, vcard=None, jid=None, block=True, ifrom=None,
callback=None, timeout=None): callback=None, timeout=None):
if self.xmpp.is_component: if self.xmpp.is_component:
self.api['set_vcard'](jid, None, ifrom, vcard) self.api['set_vcard'](jid, None, ifrom, vcard)

View File

@ -39,5 +39,3 @@ class AuthFeature(ElementBase):
interfaces = set() interfaces = set()
plugin_tag_map = {} plugin_tag_map = {}
plugin_attrib_map = {} plugin_attrib_map = {}

View File

@ -40,33 +40,33 @@ class XEP_0080(BasePlugin):
accuracy -- Horizontal GPS error in meters. accuracy -- Horizontal GPS error in meters.
alt -- Altitude in meters above or below sea level. alt -- Altitude in meters above or below sea level.
area -- A named area such as a campus or neighborhood. area -- A named area such as a campus or neighborhood.
bearing -- GPS bearing (direction in which the entity is bearing -- GPS bearing (direction in which the entity is
heading to reach its next waypoint), measured in heading to reach its next waypoint), measured in
decimal degrees relative to true north. decimal degrees relative to true north.
building -- A specific building on a street or in an area. building -- A specific building on a street or in an area.
country -- The nation where the user is located. country -- The nation where the user is located.
countrycode -- The ISO 3166 two-letter country code. countrycode -- The ISO 3166 two-letter country code.
datum -- GPS datum. datum -- GPS datum.
description -- A natural-language name for or description of description -- A natural-language name for or description of
the location. the location.
error -- Horizontal GPS error in arc minutes. Obsoleted by error -- Horizontal GPS error in arc minutes. Obsoleted by
the accuracy parameter. the accuracy parameter.
floor -- A particular floor in a building. floor -- A particular floor in a building.
lat -- Latitude in decimal degrees North. lat -- Latitude in decimal degrees North.
locality -- A locality within the administrative region, such locality -- A locality within the administrative region, such
as a town or city. as a town or city.
lon -- Longitude in decimal degrees East. lon -- Longitude in decimal degrees East.
postalcode -- A code used for postal delivery. postalcode -- A code used for postal delivery.
region -- An administrative region of the nation, such region -- An administrative region of the nation, such
as a state or province. as a state or province.
room -- A particular room in a building. room -- A particular room in a building.
speed -- The speed at which the entity is moving, speed -- The speed at which the entity is moving,
in meters per second. in meters per second.
street -- A thoroughfare within the locality, or a crossing street -- A thoroughfare within the locality, or a crossing
of two thoroughfares. of two thoroughfares.
text -- A catch-all element that captures any other text -- A catch-all element that captures any other
information about the location. information about the location.
timestamp -- UTC timestamp specifying the moment when the timestamp -- UTC timestamp specifying the moment when the
reading was taken. reading was taken.
uri -- A URI or URL pointing to information about uri -- A URI or URL pointing to information about
the location. the location.
@ -115,7 +115,7 @@ class XEP_0080(BasePlugin):
be executed when a reply stanza is received. be executed when a reply stanza is received.
""" """
geoloc = Geoloc() geoloc = Geoloc()
return self.xmpp['xep_0163'].publish(geoloc, return self.xmpp['xep_0163'].publish(geoloc,
ifrom=ifrom, ifrom=ifrom,
block=block, block=block,
callback=callback, callback=callback,

View File

@ -31,33 +31,33 @@ class Geoloc(ElementBase):
accuracy -- Horizontal GPS error in meters. accuracy -- Horizontal GPS error in meters.
alt -- Altitude in meters above or below sea level. alt -- Altitude in meters above or below sea level.
area -- A named area such as a campus or neighborhood. area -- A named area such as a campus or neighborhood.
bearing -- GPS bearing (direction in which the entity is bearing -- GPS bearing (direction in which the entity is
heading to reach its next waypoint), measured in heading to reach its next waypoint), measured in
decimal degrees relative to true north. decimal degrees relative to true north.
building -- A specific building on a street or in an area. building -- A specific building on a street or in an area.
country -- The nation where the user is located. country -- The nation where the user is located.
countrycode -- The ISO 3166 two-letter country code. countrycode -- The ISO 3166 two-letter country code.
datum -- GPS datum. datum -- GPS datum.
description -- A natural-language name for or description of description -- A natural-language name for or description of
the location. the location.
error -- Horizontal GPS error in arc minutes. Obsoleted by error -- Horizontal GPS error in arc minutes. Obsoleted by
the accuracy parameter. the accuracy parameter.
floor -- A particular floor in a building. floor -- A particular floor in a building.
lat -- Latitude in decimal degrees North. lat -- Latitude in decimal degrees North.
locality -- A locality within the administrative region, such locality -- A locality within the administrative region, such
as a town or city. as a town or city.
lon -- Longitude in decimal degrees East. lon -- Longitude in decimal degrees East.
postalcode -- A code used for postal delivery. postalcode -- A code used for postal delivery.
region -- An administrative region of the nation, such region -- An administrative region of the nation, such
as a state or province. as a state or province.
room -- A particular room in a building. room -- A particular room in a building.
speed -- The speed at which the entity is moving, speed -- The speed at which the entity is moving,
in meters per second. in meters per second.
street -- A thoroughfare within the locality, or a crossing street -- A thoroughfare within the locality, or a crossing
of two thoroughfares. of two thoroughfares.
text -- A catch-all element that captures any other text -- A catch-all element that captures any other
information about the location. information about the location.
timestamp -- UTC timestamp specifying the moment when the timestamp -- UTC timestamp specifying the moment when the
reading was taken. reading was taken.
uri -- A URI or URL pointing to information about uri -- A URI or URL pointing to information about
the location. the location.
@ -65,10 +65,10 @@ class Geoloc(ElementBase):
namespace = 'http://jabber.org/protocol/geoloc' namespace = 'http://jabber.org/protocol/geoloc'
name = 'geoloc' name = 'geoloc'
interfaces = set(('accuracy', 'alt', 'area', 'bearing', 'building', interfaces = set(('accuracy', 'alt', 'area', 'bearing', 'building',
'country', 'countrycode', 'datum', 'dscription', 'country', 'countrycode', 'datum', 'dscription',
'error', 'floor', 'lat', 'locality', 'lon', 'error', 'floor', 'lat', 'locality', 'lon',
'postalcode', 'region', 'room', 'speed', 'street', 'postalcode', 'region', 'room', 'speed', 'street',
'text', 'timestamp', 'uri')) 'text', 'timestamp', 'uri'))
sub_interfaces = interfaces sub_interfaces = interfaces
plugin_attrib = name plugin_attrib = name
@ -88,7 +88,7 @@ class Geoloc(ElementBase):
""" """
self._set_sub_text('accuracy', text=str(accuracy)) self._set_sub_text('accuracy', text=str(accuracy))
return self return self
def get_accuracy(self): def get_accuracy(self):
""" """
Return the value of the <accuracy> element as an integer. Return the value of the <accuracy> element as an integer.
@ -111,7 +111,7 @@ class Geoloc(ElementBase):
""" """
self._set_sub_text('alt', text=str(alt)) self._set_sub_text('alt', text=str(alt))
return self return self
def get_alt(self): def get_alt(self):
""" """
Return the value of the <alt> element as an integer. Return the value of the <alt> element as an integer.
@ -130,8 +130,8 @@ class Geoloc(ElementBase):
Set the value of the <bearing> element. Set the value of the <bearing> element.
Arguments: Arguments:
bearing -- GPS bearing (direction in which the entity is heading bearing -- GPS bearing (direction in which the entity is heading
to reach its next waypoint), measured in decimal to reach its next waypoint), measured in decimal
degrees relative to true north degrees relative to true north
""" """
self._set_sub_text('bearing', text=str(bearing)) self._set_sub_text('bearing', text=str(bearing))
@ -155,7 +155,7 @@ class Geoloc(ElementBase):
Set the value of the <error> element. Set the value of the <error> element.
Arguments: Arguments:
error -- Horizontal GPS error in arc minutes; this error -- Horizontal GPS error in arc minutes; this
element is deprecated in favor of <accuracy/> element is deprecated in favor of <accuracy/>
""" """
self._set_sub_text('error', text=str(error)) self._set_sub_text('error', text=str(error))
@ -183,7 +183,7 @@ class Geoloc(ElementBase):
""" """
self._set_sub_text('lat', text=str(lat)) self._set_sub_text('lat', text=str(lat))
return self return self
def get_lat(self): def get_lat(self):
""" """
Return the value of the <lat> element as a float. Return the value of the <lat> element as a float.
@ -196,7 +196,7 @@ class Geoloc(ElementBase):
return float(p) return float(p)
except ValueError: except ValueError:
return None return None
def set_lon(self, lon): def set_lon(self, lon):
""" """
Set the value of the <lon> element. Set the value of the <lon> element.
@ -225,12 +225,12 @@ class Geoloc(ElementBase):
Set the value of the <speed> element. Set the value of the <speed> element.
Arguments: Arguments:
speed -- The speed at which the entity is moving, speed -- The speed at which the entity is moving,
in meters per second in meters per second
""" """
self._set_sub_text('speed', text=str(speed)) self._set_sub_text('speed', text=str(speed))
return self return self
def get_speed(self): def get_speed(self):
""" """
Return the value of the <speed> element as a float. Return the value of the <speed> element as a float.

View File

@ -42,6 +42,7 @@ def format_date(time_obj):
time_obj = time_obj.date() time_obj = time_obj.date()
return time_obj.isoformat() return time_obj.isoformat()
def format_time(time_obj): def format_time(time_obj):
""" """
Return a formatted string version of a time object. Return a formatted string version of a time object.
@ -60,6 +61,7 @@ def format_time(time_obj):
return '%sZ' % timestamp return '%sZ' % timestamp
return timestamp return timestamp
def format_datetime(time_obj): def format_datetime(time_obj):
""" """
Return a formatted string version of a datetime object. Return a formatted string version of a datetime object.
@ -76,6 +78,7 @@ def format_datetime(time_obj):
return '%sZ' % timestamp return '%sZ' % timestamp
return timestamp return timestamp
def date(year=None, month=None, day=None, obj=False): def date(year=None, month=None, day=None, obj=False):
""" """
Create a date only timestamp for the given instant. Create a date only timestamp for the given instant.
@ -98,9 +101,10 @@ def date(year=None, month=None, day=None, obj=False):
day = today.day day = today.day
value = dt.date(year, month, day) value = dt.date(year, month, day)
if obj: if obj:
return value return value
return format_date(value) return format_date(value)
def time(hour=None, min=None, sec=None, micro=None, offset=None, obj=False): def time(hour=None, min=None, sec=None, micro=None, offset=None, obj=False):
""" """
Create a time only timestamp for the given instant. Create a time only timestamp for the given instant.
@ -136,6 +140,7 @@ def time(hour=None, min=None, sec=None, micro=None, offset=None, obj=False):
return value return value
return format_time(value) return format_time(value)
def datetime(year=None, month=None, day=None, hour=None, def datetime(year=None, month=None, day=None, hour=None,
min=None, sec=None, micro=None, offset=None, min=None, sec=None, micro=None, offset=None,
separators=True, obj=False): separators=True, obj=False):
@ -181,7 +186,7 @@ def datetime(year=None, month=None, day=None, hour=None,
value = dt.datetime(year, month, day, hour, value = dt.datetime(year, month, day, hour,
min, sec, micro, offset) min, sec, micro, offset)
if obj: if obj:
return value return value
return format_datetime(value) return format_datetime(value)

View File

@ -14,5 +14,3 @@ from sleekxmpp.plugins.xep_0084.avatar import XEP_0084
register_plugin(XEP_0084) register_plugin(XEP_0084)

View File

@ -38,7 +38,7 @@ class XEP_0084(BasePlugin):
def retrieve_avatar(self, jid, id, url=None, ifrom=None, block=True, def retrieve_avatar(self, jid, id, url=None, ifrom=None, block=True,
callback=None, timeout=None): callback=None, timeout=None):
return self.xmpp['xep_0060'].get_item(jid, Data.namespace, id, return self.xmpp['xep_0060'].get_item(jid, Data.namespace, id,
ifrom=ifrom, ifrom=ifrom,
block=block, block=block,
callback=callback, callback=callback,

View File

@ -47,28 +47,28 @@ class LegacyError(ElementBase):
interfaces = set(('condition',)) interfaces = set(('condition',))
overrides = ['set_condition'] overrides = ['set_condition']
error_map = {'bad-request': ('modify','400'), error_map = {'bad-request': ('modify', '400'),
'conflict': ('cancel','409'), 'conflict': ('cancel', '409'),
'feature-not-implemented': ('cancel','501'), 'feature-not-implemented': ('cancel', '501'),
'forbidden': ('auth','403'), 'forbidden': ('auth', '403'),
'gone': ('modify','302'), 'gone': ('modify', '302'),
'internal-server-error': ('wait','500'), 'internal-server-error': ('wait', '500'),
'item-not-found': ('cancel','404'), 'item-not-found': ('cancel', '404'),
'jid-malformed': ('modify','400'), 'jid-malformed': ('modify', '400'),
'not-acceptable': ('modify','406'), 'not-acceptable': ('modify', '406'),
'not-allowed': ('cancel','405'), 'not-allowed': ('cancel', '405'),
'not-authorized': ('auth','401'), 'not-authorized': ('auth', '401'),
'payment-required': ('auth','402'), 'payment-required': ('auth', '402'),
'recipient-unavailable': ('wait','404'), 'recipient-unavailable': ('wait', '404'),
'redirect': ('modify','302'), 'redirect': ('modify', '302'),
'registration-required': ('auth','407'), 'registration-required': ('auth', '407'),
'remote-server-not-found': ('cancel','404'), 'remote-server-not-found': ('cancel', '404'),
'remote-server-timeout': ('wait','504'), 'remote-server-timeout': ('wait', '504'),
'resource-constraint': ('wait','500'), 'resource-constraint': ('wait', '500'),
'service-unavailable': ('cancel','503'), 'service-unavailable': ('cancel', '503'),
'subscription-required': ('auth','407'), 'subscription-required': ('auth', '407'),
'undefined-condition': (None,'500'), 'undefined-condition': (None, '500'),
'unexpected-request': ('wait','400')} 'unexpected-request': ('wait', '400')}
def setup(self, xml): def setup(self, xml):
"""Don't create XML for the plugin.""" """Don't create XML for the plugin."""

View File

@ -34,7 +34,7 @@ class XEP_0107(BasePlugin):
register_stanza_plugin(Message, UserMood) register_stanza_plugin(Message, UserMood)
self.xmpp['xep_0163'].register_pep('user_mood', UserMood) self.xmpp['xep_0163'].register_pep('user_mood', UserMood)
def publish_mood(self, value=None, text=None, options=None, def publish_mood(self, value=None, text=None, options=None,
ifrom=None, block=True, callback=None, timeout=None): ifrom=None, block=True, callback=None, timeout=None):
""" """
Publish the user's current mood. Publish the user's current mood.
@ -79,7 +79,7 @@ class XEP_0107(BasePlugin):
be executed when a reply stanza is received. be executed when a reply stanza is received.
""" """
mood = UserMood() mood = UserMood()
return self.xmpp['xep_0163'].publish(mood, return self.xmpp['xep_0163'].publish(mood,
node=UserMood.namespace, node=UserMood.namespace,
ifrom=ifrom, ifrom=ifrom,
block=block, block=block,

View File

@ -21,7 +21,7 @@ class UserActivity(ElementBase):
'talking', 'traveling', 'undefined', 'working']) 'talking', 'traveling', 'undefined', 'working'])
specific = set(['at_the_spa', 'brushing_teeth', 'buying_groceries', specific = set(['at_the_spa', 'brushing_teeth', 'buying_groceries',
'cleaning', 'coding', 'commuting', 'cooking', 'cycling', 'cleaning', 'coding', 'commuting', 'cooking', 'cycling',
'dancing', 'day_off', 'doing_maintenance', 'dancing', 'day_off', 'doing_maintenance',
'doing_the_dishes', 'doing_the_laundry', 'driving', 'doing_the_dishes', 'doing_the_laundry', 'driving',
'fishing', 'gaming', 'gardening', 'getting_a_haircut', 'fishing', 'gaming', 'gardening', 'getting_a_haircut',
'going_out', 'hanging_out', 'having_a_beer', 'going_out', 'hanging_out', 'having_a_beer',
@ -31,11 +31,11 @@ class UserActivity(ElementBase):
'jogging', 'on_a_bus', 'on_a_plane', 'on_a_train', 'jogging', 'on_a_bus', 'on_a_plane', 'on_a_train',
'on_a_trip', 'on_the_phone', 'on_vacation', 'on_a_trip', 'on_the_phone', 'on_vacation',
'on_video_phone', 'other', 'partying', 'playing_sports', 'on_video_phone', 'other', 'partying', 'playing_sports',
'praying', 'reading', 'rehearsing', 'running', 'praying', 'reading', 'rehearsing', 'running',
'running_an_errand', 'scheduled_holiday', 'shaving', 'running_an_errand', 'scheduled_holiday', 'shaving',
'shopping', 'skiing', 'sleeping', 'smoking', 'shopping', 'skiing', 'sleeping', 'smoking',
'socializing', 'studying', 'sunbathing', 'swimming', 'socializing', 'studying', 'sunbathing', 'swimming',
'taking_a_bath', 'taking_a_shower', 'thinking', 'taking_a_bath', 'taking_a_shower', 'thinking',
'walking', 'walking_the_dog', 'watching_a_movie', 'walking', 'walking_the_dog', 'watching_a_movie',
'watching_tv', 'working_out', 'writing']) 'watching_tv', 'working_out', 'writing'])
@ -46,7 +46,7 @@ class UserActivity(ElementBase):
if isinstance(value, tuple) or isinstance(value, list): if isinstance(value, tuple) or isinstance(value, list):
general = value[0] general = value[0]
specific = value[1] specific = value[1]
if general in self.general: if general in self.general:
gen_xml = ET.Element('{%s}%s' % (self.namespace, general)) gen_xml = ET.Element('{%s}%s' % (self.namespace, general))
if specific: if specific:

View File

@ -29,7 +29,7 @@ class XEP_0108(BasePlugin):
def plugin_init(self): def plugin_init(self):
self.xmpp['xep_0163'].register_pep('user_activity', UserActivity) self.xmpp['xep_0163'].register_pep('user_activity', UserActivity)
def publish_activity(self, general, specific=None, text=None, options=None, def publish_activity(self, general, specific=None, text=None, options=None,
ifrom=None, block=True, callback=None, timeout=None): ifrom=None, block=True, callback=None, timeout=None):
""" """
Publish the user's current activity. Publish the user's current activity.
@ -76,7 +76,7 @@ class XEP_0108(BasePlugin):
be executed when a reply stanza is received. be executed when a reply stanza is received.
""" """
activity = UserActivity() activity = UserActivity()
return self.xmpp['xep_0163'].publish(activity, return self.xmpp['xep_0163'].publish(activity,
node=UserActivity.namespace, node=UserActivity.namespace,
ifrom=ifrom, ifrom=ifrom,
block=block, block=block,

View File

@ -35,7 +35,7 @@ class XEP_0115(BasePlugin):
stanza = stanza stanza = stanza
def plugin_init(self): def plugin_init(self):
self.hashes = {'sha-1': hashlib.sha1, self.hashes = {'sha-1': hashlib.sha1,
'sha1': hashlib.sha1, 'sha1': hashlib.sha1,
'md5': hashlib.md5} 'md5': hashlib.md5}
@ -124,7 +124,7 @@ class XEP_0115(BasePlugin):
existing_verstring = self.get_verstring(pres['from'].full) existing_verstring = self.get_verstring(pres['from'].full)
if str(existing_verstring) == str(pres['caps']['ver']): if str(existing_verstring) == str(pres['caps']['ver']):
return return
if pres['caps']['hash'] not in self.hashes: if pres['caps']['hash'] not in self.hashes:
try: try:
log.debug("Unknown caps hash: %s", pres['caps']['hash']) log.debug("Unknown caps hash: %s", pres['caps']['hash'])
@ -132,7 +132,7 @@ class XEP_0115(BasePlugin):
return return
except XMPPError: except XMPPError:
return return
log.debug("New caps verification string: %s", pres['caps']['ver']) log.debug("New caps verification string: %s", pres['caps']['ver'])
try: try:
node = '%s#%s' % (pres['caps']['node'], pres['caps']['ver']) node = '%s#%s' % (pres['caps']['node'], pres['caps']['ver'])
@ -140,7 +140,7 @@ class XEP_0115(BasePlugin):
if isinstance(caps, Iq): if isinstance(caps, Iq):
caps = caps['disco_info'] caps = caps['disco_info']
if self._validate_caps(caps, pres['caps']['hash'], if self._validate_caps(caps, pres['caps']['hash'],
pres['caps']['ver']): pres['caps']['ver']):
self.assign_verstring(pres['from'], pres['caps']['ver']) self.assign_verstring(pres['from'], pres['caps']['ver'])
@ -173,7 +173,8 @@ class XEP_0115(BasePlugin):
form_types.append(f_type) form_types.append(f_type)
deduped_form_types.add(f_type) deduped_form_types.add(f_type)
if len(form_types) != len(deduped_form_types): if len(form_types) != len(deduped_form_types):
log.debug("Duplicated FORM_TYPE values, invalid for caps") log.debug("Duplicated FORM_TYPE values, " + \
"invalid for caps")
return False return False
if len(f_type) > 1: if len(f_type) > 1:
@ -183,7 +184,8 @@ class XEP_0115(BasePlugin):
return False return False
if stanza['fields']['FORM_TYPE']['type'] != 'hidden': if stanza['fields']['FORM_TYPE']['type'] != 'hidden':
log.debug("Field FORM_TYPE type not 'hidden', ignoring form for caps") log.debug("Field FORM_TYPE type not 'hidden', " + \
"ignoring form for caps")
caps.xml.remove(stanza.xml) caps.xml.remove(stanza.xml)
else: else:
log.debug("No FORM_TYPE found, ignoring form for caps") log.debug("No FORM_TYPE found, ignoring form for caps")
@ -212,7 +214,7 @@ class XEP_0115(BasePlugin):
identities = sorted(('/'.join(i) for i in identities)) identities = sorted(('/'.join(i) for i in identities))
features = sorted(info['features']) features = sorted(info['features'])
S += '<'.join(identities) + '<' S += '<'.join(identities) + '<'
S += '<'.join(features) + '<' S += '<'.join(features) + '<'
@ -254,7 +256,7 @@ class XEP_0115(BasePlugin):
info = info['disco_info'] info = info['disco_info']
ver = self.generate_verstring(info, self.hash) ver = self.generate_verstring(info, self.hash)
self.xmpp['xep_0030'].set_info( self.xmpp['xep_0030'].set_info(
jid=jid, jid=jid,
node='%s#%s' % (self.caps_node, ver), node='%s#%s' % (self.caps_node, ver),
info=info) info=info)
self.cache_caps(ver, info) self.cache_caps(ver, info)

View File

@ -69,7 +69,7 @@ class StaticCaps(object):
return True return True
try: try:
info = self.disco.get_info(jid=jid, node=node, info = self.disco.get_info(jid=jid, node=node,
ifrom=ifrom, **data) ifrom=ifrom, **data)
info = self.disco._wrap(ifrom, jid, info, True) info = self.disco._wrap(ifrom, jid, info, True)
return feature in info['disco_info']['features'] return feature in info['disco_info']['features']
@ -99,7 +99,7 @@ class StaticCaps(object):
be skipped, even if a result has already been be skipped, even if a result has already been
cached. Defaults to false. cached. Defaults to false.
""" """
identity = (data.get('category', None), identity = (data.get('category', None),
data.get('itype', None), data.get('itype', None),
data.get('lang', None)) data.get('lang', None))
@ -114,7 +114,7 @@ class StaticCaps(object):
return True return True
try: try:
info = self.disco.get_info(jid=jid, node=node, info = self.disco.get_info(jid=jid, node=node,
ifrom=ifrom, **data) ifrom=ifrom, **data)
info = self.disco._wrap(ifrom, jid, info, True) info = self.disco._wrap(ifrom, jid, info, True)
return identity in map(trunc, info['disco_info']['identities']) return identity in map(trunc, info['disco_info']['identities'])

View File

@ -14,7 +14,7 @@ class UserTune(ElementBase):
name = 'tune' name = 'tune'
namespace = 'http://jabber.org/protocol/tune' namespace = 'http://jabber.org/protocol/tune'
plugin_attrib = 'tune' plugin_attrib = 'tune'
interfaces = set(['artist', 'length', 'rating', 'source', interfaces = set(['artist', 'length', 'rating', 'source',
'title', 'track', 'uri']) 'title', 'track', 'uri'])
sub_interfaces = interfaces sub_interfaces = interfaces

View File

@ -30,7 +30,7 @@ class XEP_0118(BasePlugin):
self.xmpp['xep_0163'].register_pep('user_tune', UserTune) self.xmpp['xep_0163'].register_pep('user_tune', UserTune)
def publish_tune(self, artist=None, length=None, rating=None, source=None, def publish_tune(self, artist=None, length=None, rating=None, source=None,
title=None, track=None, uri=None, options=None, title=None, track=None, uri=None, options=None,
ifrom=None, block=True, callback=None, timeout=None): ifrom=None, block=True, callback=None, timeout=None):
""" """
Publish the user's current tune. Publish the user's current tune.
@ -61,7 +61,7 @@ class XEP_0118(BasePlugin):
tune['title'] = title tune['title'] = title
tune['track'] = track tune['track'] = track
tune['uri'] = uri tune['uri'] = uri
return self.xmpp['xep_0163'].publish(tune, return self.xmpp['xep_0163'].publish(tune,
node=UserTune.namespace, node=UserTune.namespace,
options=options, options=options,
ifrom=ifrom, ifrom=ifrom,
@ -84,7 +84,7 @@ class XEP_0118(BasePlugin):
be executed when a reply stanza is received. be executed when a reply stanza is received.
""" """
tune = UserTune() tune = UserTune()
return self.xmpp['xep_0163'].publish(tune, return self.xmpp['xep_0163'].publish(tune,
node=UserTune.namespace, node=UserTune.namespace,
ifrom=ifrom, ifrom=ifrom,
block=block, block=block,

View File

@ -45,7 +45,7 @@ class XEP_0153(BasePlugin):
self.api.register(self._set_hash, 'set_hash', default=True) self.api.register(self._set_hash, 'set_hash', default=True)
self.api.register(self._get_hash, 'get_hash', default=True) self.api.register(self._get_hash, 'get_hash', default=True)
def set_avatar(self, jid=None, avatar=None, mtype=None, block=True, def set_avatar(self, jid=None, avatar=None, mtype=None, block=True,
timeout=None, callback=None): timeout=None, callback=None):
vcard = self.xmpp['xep_0054'].get_vcard(jid, cached=True) vcard = self.xmpp['xep_0054'].get_vcard(jid, cached=True)
vcard = vcard['vcard_temp'] vcard = vcard['vcard_temp']
@ -69,7 +69,7 @@ class XEP_0153(BasePlugin):
own_jid = (jid.bare == self.xmpp.boundjid.bare) own_jid = (jid.bare == self.xmpp.boundjid.bare)
if self.xmpp.is_component: if self.xmpp.is_component:
own_jid = (jid.domain == self.xmpp.boundjid.domain) own_jid = (jid.domain == self.xmpp.boundjid.domain)
if jid is not None: if jid is not None:
jid = jid.bare jid = jid.bare
self.api['set_hash'](jid, args=None) self.api['set_hash'](jid, args=None)
@ -77,7 +77,7 @@ class XEP_0153(BasePlugin):
self.xmpp.roster[jid].send_last_presence() self.xmpp.roster[jid].send_last_presence()
iq = self.xmpp['xep_0054'].get_vcard( iq = self.xmpp['xep_0054'].get_vcard(
jid=jid, jid=jid,
ifrom=self.xmpp.boundjid) ifrom=self.xmpp.boundjid)
data = iq['vcard_temp']['PHOTO']['BINVAL'] data = iq['vcard_temp']['PHOTO']['BINVAL']
if not data: if not data:

View File

@ -56,7 +56,7 @@ class XEP_0163(BasePlugin):
jid -- Optionally specify the JID. jid -- Optionally specify the JID.
""" """
if not isinstance(namespace, set) and not isinstance(namespace, list): if not isinstance(namespace, set) and not isinstance(namespace, list):
namespace = [namespace] namespace = [namespace]
for ns in namespace: for ns in namespace:
self.xmpp['xep_0030'].add_feature('%s+notify' % ns, self.xmpp['xep_0030'].add_feature('%s+notify' % ns,
@ -75,7 +75,7 @@ class XEP_0163(BasePlugin):
jid -- Optionally specify the JID. jid -- Optionally specify the JID.
""" """
if not isinstance(namespace, set) and not isinstance(namespace, list): if not isinstance(namespace, set) and not isinstance(namespace, list):
namespace = [namespace] namespace = [namespace]
for ns in namespace: for ns in namespace:
self.xmpp['xep_0030'].del_feature(jid=jid, self.xmpp['xep_0030'].del_feature(jid=jid,

View File

@ -78,7 +78,7 @@ class XEP_0172(BasePlugin):
be executed when a reply stanza is received. be executed when a reply stanza is received.
""" """
nick = UserNick() nick = UserNick()
return self.xmpp['xep_0163'].publish(nick, return self.xmpp['xep_0163'].publish(nick,
node=UserNick.namespace, node=UserNick.namespace,
ifrom=ifrom, ifrom=ifrom,
block=block, block=block,

View File

@ -100,13 +100,13 @@ class XEP_0184(BasePlugin):
if not isinstance(stanza, Message): if not isinstance(stanza, Message):
return stanza return stanza
if stanza['request_receipt']: if stanza['request_receipt']:
return stanza return stanza
if not stanza['type'] in self.ack_types: if not stanza['type'] in self.ack_types:
return stanza return stanza
if stanza['receipt']: if stanza['receipt']:
return stanza return stanza

View File

@ -82,7 +82,6 @@ class Resumed(StanzaBase):
self._set_attr('h', str(val)) self._set_attr('h', str(val))
class Failed(StanzaBase, Error): class Failed(StanzaBase, Error):
name = 'failed' name = 'failed'
namespace = 'urn:xmpp:sm:3' namespace = 'urn:xmpp:sm:3'
@ -106,7 +105,7 @@ class StreamManagement(ElementBase):
self.del_required() self.del_required()
if val: if val:
self._set_sub_text('required', '', keep=True) self._set_sub_text('required', '', keep=True)
def del_required(self): def del_required(self):
self._del_sub('required') self._del_sub('required')
@ -117,7 +116,7 @@ class StreamManagement(ElementBase):
self.del_optional() self.del_optional()
if val: if val:
self._set_sub_text('optional', '', keep=True) self._set_sub_text('optional', '', keep=True)
def del_optional(self): def del_optional(self):
self._del_sub('optional') self._del_sub('optional')

View File

@ -21,7 +21,7 @@ from sleekxmpp.plugins.xep_0198 import stanza
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
MAX_SEQ = 2**32 MAX_SEQ = 2 ** 32
class XEP_0198(BasePlugin): class XEP_0198(BasePlugin):
@ -69,7 +69,7 @@ class XEP_0198(BasePlugin):
self.enabled = threading.Event() self.enabled = threading.Event()
self.unacked_queue = collections.deque() self.unacked_queue = collections.deque()
self.seq_lock = threading.Lock() self.seq_lock = threading.Lock()
self.handled_lock = threading.Lock() self.handled_lock = threading.Lock()
self.ack_lock = threading.Lock() self.ack_lock = threading.Lock()
@ -197,7 +197,7 @@ class XEP_0198(BasePlugin):
def _handle_enabled(self, stanza): def _handle_enabled(self, stanza):
"""Save the SM-ID, if provided. """Save the SM-ID, if provided.
Raises an :term:`sm_enabled` event. Raises an :term:`sm_enabled` event.
""" """
self.xmpp.features.add('stream_management') self.xmpp.features.add('stream_management')
@ -231,7 +231,7 @@ class XEP_0198(BasePlugin):
def _handle_ack(self, ack): def _handle_ack(self, ack):
"""Process a server ack by freeing acked stanzas from the queue. """Process a server ack by freeing acked stanzas from the queue.
Raises a :term:`stanza_acked` event for each acked stanza. Raises a :term:`stanza_acked` event for each acked stanza.
""" """
if ack['h'] == self.last_ack: if ack['h'] == self.last_ack:
@ -243,10 +243,10 @@ class XEP_0198(BasePlugin):
log.debug("Ack: %s, Last Ack: %s, " + \ log.debug("Ack: %s, Last Ack: %s, " + \
"Unacked: %s, Num Acked: %s, " + \ "Unacked: %s, Num Acked: %s, " + \
"Remaining: %s", "Remaining: %s",
ack['h'], ack['h'],
self.last_ack, self.last_ack,
num_unacked, num_unacked,
num_acked, num_acked,
num_unacked - num_acked) num_unacked - num_acked)
for x in range(num_acked): for x in range(num_acked):
seq, stanza = self.unacked_queue.popleft() seq, stanza = self.unacked_queue.popleft()

View File

@ -40,8 +40,12 @@ class XEP_0202(BasePlugin):
# custom function can be supplied which accepts # custom function can be supplied which accepts
# the JID of the entity to query for the time. # the JID of the entity to query for the time.
self.local_time = self.config.get('local_time', None) self.local_time = self.config.get('local_time', None)
def default_local_time(jid):
return xep_0082.datetime(offset=self.tz_offset)
if not self.local_time: if not self.local_time:
self.local_time = lambda x: xep_0082.datetime(offset=self.tz_offset) self.local_time = default_local_time
self.xmpp.registerHandler( self.xmpp.registerHandler(
Callback('Entity Time', Callback('Entity Time',

View File

@ -13,9 +13,7 @@ from sleekxmpp.plugins.xep_0203.stanza import Delay
from sleekxmpp.plugins.xep_0203.delay import XEP_0203 from sleekxmpp.plugins.xep_0203.delay import XEP_0203
register_plugin(XEP_0203) register_plugin(XEP_0203)
# Retain some backwards compatibility # Retain some backwards compatibility
xep_0203 = XEP_0203 xep_0203 = XEP_0203

View File

@ -18,13 +18,13 @@ log = logging.getLogger(__name__)
class XEP_0222(BasePlugin): class XEP_0222(BasePlugin):
""" """
XEP-0222: Persistent Storage of Public Data via PubSub XEP-0222: Persistent Storage of Public Data via PubSub
""" """
name = 'xep_0222' name = 'xep_0222'
description = 'XEP-0222: Persistent Storage of Private Data via PubSub' description = 'XEP-0222: Persistent Storage of Private Data via PubSub'
dependencies = set(['xep_0163', 'xep_0060', 'xep_0004']) dependencies = set(['xep_0163', 'xep_0060', 'xep_0004'])
profile = {'pubsub#persist_items': True, profile = {'pubsub#persist_items': True,
'pubsub#send_last_published_item': 'never'} 'pubsub#send_last_published_item': 'never'}
@ -72,8 +72,8 @@ class XEP_0222(BasePlugin):
options = self.xmpp['xep_0004'].stanza.Form() options = self.xmpp['xep_0004'].stanza.Form()
options['type'] = 'submit' options['type'] = 'submit'
options.add_field( options.add_field(
var='FORM_TYPE', var='FORM_TYPE',
ftype='hidden', ftype='hidden',
value='http://jabber.org/protocol/pubsub#publish-options') value='http://jabber.org/protocol/pubsub#publish-options')
for field, value in self.profile.items(): for field, value in self.profile.items():

View File

@ -18,7 +18,7 @@ log = logging.getLogger(__name__)
class XEP_0223(BasePlugin): class XEP_0223(BasePlugin):
""" """
XEP-0223: Persistent Storage of Private Data via PubSub XEP-0223: Persistent Storage of Private Data via PubSub
""" """
name = 'xep_0223' name = 'xep_0223'
@ -72,8 +72,8 @@ class XEP_0223(BasePlugin):
options = self.xmpp['xep_0004'].stanza.Form() options = self.xmpp['xep_0004'].stanza.Form()
options['type'] = 'submit' options['type'] = 'submit'
options.add_field( options.add_field(
var='FORM_TYPE', var='FORM_TYPE',
ftype='hidden', ftype='hidden',
value='http://jabber.org/protocol/pubsub#publish-options') value='http://jabber.org/protocol/pubsub#publish-options')
for field, value in self.profile.items(): for field, value in self.profile.items():

View File

@ -1,6 +1,6 @@
""" """
SleekXMPP: The Sleek XMPP Library SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Copyright (C) 2012 Nathanael C. Fritz,
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
This file is part of SleekXMPP. This file is part of SleekXMPP.

View File

@ -1,6 +1,6 @@
""" """
SleekXMPP: The Sleek XMPP Library SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Copyright (C) 2012 Nathanael C. Fritz,
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
This file is part of SleekXMPP. This file is part of SleekXMPP.
@ -58,7 +58,6 @@ class XEP_0231(BasePlugin):
self.api.register(self._set_bob, 'set_bob', default=True) self.api.register(self._set_bob, 'set_bob', default=True)
self.api.register(self._del_bob, 'del_bob', default=True) self.api.register(self._del_bob, 'del_bob', default=True)
def set_bob(self, data, mtype, cid=None, max_age=None): def set_bob(self, data, mtype, cid=None, max_age=None):
if cid is None: if cid is None:
cid = 'sha1+%s@bob.xmpp.org' % hashlib.sha1(data).hexdigest() cid = 'sha1+%s@bob.xmpp.org' % hashlib.sha1(data).hexdigest()
@ -73,7 +72,7 @@ class XEP_0231(BasePlugin):
return cid return cid
def get_bob(self, jid=None, cid=None, cached=True, ifrom=None, def get_bob(self, jid=None, cid=None, cached=True, ifrom=None,
block=True, timeout=None, callback=None): block=True, timeout=None, callback=None):
if cached: if cached:
data = self.api['get_bob'](None, None, ifrom, args=cid) data = self.api['get_bob'](None, None, ifrom, args=cid)
@ -112,7 +111,7 @@ class XEP_0231(BasePlugin):
iq.send() iq.send()
def _handle_bob(self, stanza): def _handle_bob(self, stanza):
self.api['set_bob'](stanza['from'], None, self.api['set_bob'](stanza['from'], None,
stanza['to'], args=stanza['bob']) stanza['to'], args=stanza['bob'])
self.xmpp.event('bob', stanza) self.xmpp.event('bob', stanza)

View File

@ -1,6 +1,6 @@
""" """
SleekXMPP: The Sleek XMPP Library SleekXMPP: The Sleek XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Copyright (C) 2012 Nathanael C. Fritz,
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
This file is part of SleekXMPP. This file is part of SleekXMPP.

View File

@ -30,7 +30,7 @@ class XEP_0258(BasePlugin):
register_stanza_plugin(Message, SecurityLabel) register_stanza_plugin(Message, SecurityLabel)
register_stanza_plugin(Iq, Catalog) register_stanza_plugin(Iq, Catalog)
def get_catalog(self, jid, ifrom=None, block=True, def get_catalog(self, jid, ifrom=None, block=True,
callback=None, timeout=None): callback=None, timeout=None):
iq = self.xmpp.Iq() iq = self.xmpp.Iq()
iq['to'] = jid iq['to'] = jid

View File

@ -33,7 +33,7 @@ class Label(ElementBase):
class DisplayMarking(ElementBase): class DisplayMarking(ElementBase):
name = 'displaymarking' name = 'displaymarking'
namespace = 'urn:xmpp:sec-label:0' namespace = 'urn:xmpp:sec-label:0'
plugin_attrib = 'display_marking' plugin_attrib = 'display_marking'
interfaces = set(['fgcolor', 'bgcolor', 'value']) interfaces = set(['fgcolor', 'bgcolor', 'value'])
def get_fgcolor(self): def get_fgcolor(self):

View File

@ -307,7 +307,7 @@ class RosterItem(object):
p['from'] = self.owner p['from'] = self.owner
p.send() p.send()
def send_presence(self, **kwargs): def send_presence(self, **kwargs):
""" """
Create, initialize, and send a Presence stanza. Create, initialize, and send a Presence stanza.

View File

@ -150,7 +150,7 @@ class Roster(object):
for node in self: for node in self:
self[node].reset() self[node].reset()
def send_presence(self, **kwargs): def send_presence(self, **kwargs):
""" """
Create, initialize, and send a Presence stanza. Create, initialize, and send a Presence stanza.

View File

@ -68,7 +68,7 @@ class RosterNode(object):
self._version = self.db.version(self.jid) self._version = self.db.version(self.jid)
for jid in self.db.entries(self.jid): for jid in self.db.entries(self.jid):
self.add(jid) self.add(jid)
@property @property
def version(self): def version(self):
"""Retrieve the roster's version ID.""" """Retrieve the roster's version ID."""
@ -149,7 +149,7 @@ class RosterNode(object):
self.db = db self.db = db
existing_entries = set(self._jids) existing_entries = set(self._jids)
new_entries = set(self.db.entries(self.jid, {})) new_entries = set(self.db.entries(self.jid, {}))
for jid in existing_entries: for jid in existing_entries:
self._jids[jid].set_backend(db, save) self._jids[jid].set_backend(db, save)
for jid in new_entries - existing_entries: for jid in new_entries - existing_entries:
@ -294,7 +294,7 @@ class RosterNode(object):
for jid in self: for jid in self:
self[jid].reset() self[jid].reset()
def send_presence(self, **kwargs): def send_presence(self, **kwargs):
""" """
Create, initialize, and send a Presence stanza. Create, initialize, and send a Presence stanza.

View File

@ -51,7 +51,7 @@ class Error(ElementBase):
namespace = 'jabber:client' namespace = 'jabber:client'
name = 'error' name = 'error'
plugin_attrib = 'error' plugin_attrib = 'error'
interfaces = set(('code', 'condition', 'text', 'type', interfaces = set(('code', 'condition', 'text', 'type',
'gone', 'redirect')) 'gone', 'redirect'))
sub_interfaces = set(('text',)) sub_interfaces = set(('text',))
plugin_attrib_map = {} plugin_attrib_map = {}

View File

@ -78,7 +78,8 @@ class RootStanza(StanzaBase):
self['error']['type'] = 'cancel' self['error']['type'] = 'cancel'
self.send() self.send()
# log the error # log the error
log.exception('Error handling {%s}%s stanza' , self.namespace, self.name) log.exception('Error handling {%s}%s stanza',
self.namespace, self.name)
# Finally raise the exception to a global exception handler # Finally raise the exception to a global exception handler
self.stream.exception(e) self.stream.exception(e)

View File

@ -47,7 +47,7 @@ class Roster(ElementBase):
roster versioning. roster versioning.
""" """
return self.xml.attrib.get('ver', None) return self.xml.attrib.get('ver', None)
def set_ver(self, ver): def set_ver(self, ver):
""" """
Ensure handling an empty ver attribute propery. Ensure handling an empty ver attribute propery.
@ -101,7 +101,7 @@ class Roster(ElementBase):
items[item['jid']] = item.values items[item['jid']] = item.values
# Remove extra JID reference to keep everything # Remove extra JID reference to keep everything
# backward compatible # backward compatible
del items[item['jid']]['jid'] del items[item['jid']]['jid']
del items[item['jid']]['lang'] del items[item['jid']]['lang']
return items return items

View File

@ -79,4 +79,3 @@ class StreamError(Error, StanzaBase):
def del_see_other_host(self): def del_see_other_host(self):
self._del_sub('{%s}see-other-host' % self.condition_ns) self._del_sub('{%s}see-other-host' % self.condition_ns)

View File

@ -336,7 +336,6 @@ class SleekTest(unittest.TestCase):
self.xmpp.default_lang = None self.xmpp.default_lang = None
self.xmpp.peer_default_lang = None self.xmpp.peer_default_lang = None
# We will use this to wait for the session_start event # We will use this to wait for the session_start event
# for live connections. # for live connections.
skip_queue = queue.Queue() skip_queue = queue.Queue()

View File

@ -7,11 +7,12 @@ try:
from pyasn1.type.univ import Any, ObjectIdentifier, OctetString from pyasn1.type.univ import Any, ObjectIdentifier, OctetString
from pyasn1.type.char import BMPString, IA5String, UTF8String from pyasn1.type.char import BMPString, IA5String, UTF8String
from pyasn1.type.useful import GeneralizedTime from pyasn1.type.useful import GeneralizedTime
from pyasn1_modules.rfc2459 import Certificate, DirectoryString, SubjectAltName, GeneralNames, GeneralName from pyasn1_modules.rfc2459 import (Certificate, DirectoryString,
SubjectAltName, GeneralNames,
GeneralName)
from pyasn1_modules.rfc2459 import id_ce_subjectAltName as SUBJECT_ALT_NAME from pyasn1_modules.rfc2459 import id_ce_subjectAltName as SUBJECT_ALT_NAME
from pyasn1_modules.rfc2459 import id_at_commonName as COMMON_NAME from pyasn1_modules.rfc2459 import id_at_commonName as COMMON_NAME
XMPP_ADDR = ObjectIdentifier('1.3.6.1.5.5.7.8.5') XMPP_ADDR = ObjectIdentifier('1.3.6.1.5.5.7.8.5')
SRV_NAME = ObjectIdentifier('1.3.6.1.5.5.7.8.7') SRV_NAME = ObjectIdentifier('1.3.6.1.5.5.7.8.7')
@ -149,7 +150,7 @@ def verify(expected, raw_cert):
expected_wild = expected[expected.index('.'):] expected_wild = expected[expected.index('.'):]
expected_srv = '_xmpp-client.%s' % expected expected_srv = '_xmpp-client.%s' % expected
for name in cert_names['XMPPAddr']: for name in cert_names['XMPPAddr']:
if name == expected: if name == expected:
return True return True
for name in cert_names['SRV']: for name in cert_names['SRV']:

View File

@ -49,7 +49,7 @@ class BaseHandler(object):
def match(self, xml): def match(self, xml):
"""Compare a stanza or XML object with the handler's matcher. """Compare a stanza or XML object with the handler's matcher.
:param xml: An XML or :param xml: An XML or
:class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` object :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` object
""" """
return self._matcher.match(xml) return self._matcher.match(xml)
@ -73,7 +73,7 @@ class BaseHandler(object):
self._payload = payload self._payload = payload
def check_delete(self): def check_delete(self):
"""Check if the handler should be removed from the list """Check if the handler should be removed from the list
of stream handlers. of stream handlers.
""" """
return self._destroy return self._destroy

View File

@ -33,7 +33,7 @@ class Callback(BaseHandler):
:param matcher: A :class:`~sleekxmpp.xmlstream.matcher.base.MatcherBase` :param matcher: A :class:`~sleekxmpp.xmlstream.matcher.base.MatcherBase`
derived object for matching stanza objects. derived object for matching stanza objects.
:param pointer: The function to execute during callback. :param pointer: The function to execute during callback.
:param bool thread: **DEPRECATED.** Remains only for :param bool thread: **DEPRECATED.** Remains only for
backwards compatibility. backwards compatibility.
:param bool once: Indicates if the handler should be used only :param bool once: Indicates if the handler should be used only
once. Defaults to False. once. Defaults to False.

View File

@ -34,9 +34,9 @@ class MatchXMLMask(MatcherBase):
<message xmlns="jabber:client"><body /></message> <message xmlns="jabber:client"><body /></message>
Use of XMLMask is discouraged, and Use of XMLMask is discouraged, and
:class:`~sleekxmpp.xmlstream.matcher.xpath.MatchXPath` or :class:`~sleekxmpp.xmlstream.matcher.xpath.MatchXPath` or
:class:`~sleekxmpp.xmlstream.matcher.stanzapath.StanzaPath` :class:`~sleekxmpp.xmlstream.matcher.stanzapath.StanzaPath`
should be used instead. should be used instead.
The use of namespaces in the mask comparison is controlled by The use of namespaces in the mask comparison is controlled by

View File

@ -57,7 +57,7 @@ class Task(object):
#: The keyword arguments to pass to :attr:`callback`. #: The keyword arguments to pass to :attr:`callback`.
self.kwargs = kwargs or {} self.kwargs = kwargs or {}
#: Indicates if the task should repeat after executing, #: Indicates if the task should repeat after executing,
#: using the same :attr:`seconds` delay. #: using the same :attr:`seconds` delay.
self.repeat = repeat self.repeat = repeat
@ -103,7 +103,7 @@ class Scheduler(object):
def __init__(self, parentstop=None): def __init__(self, parentstop=None):
#: A queue for storing tasks #: A queue for storing tasks
self.addq = queue.Queue() self.addq = queue.Queue()
#: A list of tasks in order of execution time. #: A list of tasks in order of execution time.
self.schedule = [] self.schedule = []

View File

@ -45,7 +45,7 @@ def register_stanza_plugin(stanza, plugin, iterable=False, overrides=False):
substanzas for the parent, using ``parent['substanzas']``. If the substanzas for the parent, using ``parent['substanzas']``. If the
attribute ``plugin_multi_attrib`` was defined for the plugin, then attribute ``plugin_multi_attrib`` was defined for the plugin, then
the substanza set can be filtered to only instances of the plugin the substanza set can be filtered to only instances of the plugin
class. For example, given a plugin class ``Foo`` with class. For example, given a plugin class ``Foo`` with
``plugin_multi_attrib = 'foos'`` then:: ``plugin_multi_attrib = 'foos'`` then::
parent['foos'] parent['foos']
@ -99,6 +99,14 @@ def multifactory(stanza, plugin_attrib):
""" """
Returns a ElementBase class for handling reoccuring child stanzas Returns a ElementBase class for handling reoccuring child stanzas
""" """
def plugin_filter(self):
return lambda x: isinstance(x, self._multistanza)
def plugin_lang_filter(self, lang):
return lambda x: isinstance(x, self._multistanza) and \
x['lang'] == lang
class Multi(ElementBase): class Multi(ElementBase):
""" """
Template class for multifactory Template class for multifactory
@ -109,9 +117,9 @@ def multifactory(stanza, plugin_attrib):
def get_multi(self, lang=None): def get_multi(self, lang=None):
parent = self.parent() parent = self.parent()
if not lang or lang == '*': if not lang or lang == '*':
res = filter(lambda sub: isinstance(sub, self._multistanza), parent) res = filter(plugin_filter(self), parent)
else: else:
res = filter(lambda sub: isinstance(sub, self._multistanza) and sub['lang'] == lang, parent) res = filter(plugin_filter(self, lang), parent)
return list(res) return list(res)
def set_multi(self, val, lang=None): def set_multi(self, val, lang=None):
@ -124,9 +132,9 @@ def multifactory(stanza, plugin_attrib):
def del_multi(self, lang=None): def del_multi(self, lang=None):
parent = self.parent() parent = self.parent()
if not lang or lang == '*': if not lang or lang == '*':
res = filter(lambda sub: isinstance(sub, self._multistanza), parent) res = filter(plugin_filter(self), parent)
else: else:
res = filter(lambda sub: isinstance(sub, self._multistanza) and sub['lang'] == lang, parent) res = filter(plugin_filter(self, lang), parent)
res = list(res) res = list(res)
if not res: if not res:
del parent.plugins[(plugin_attrib, None)] del parent.plugins[(plugin_attrib, None)]
@ -253,8 +261,10 @@ class ElementBase(object):
directly from the parent stanza, as shown below, but retrieving directly from the parent stanza, as shown below, but retrieving
information will require all interfaces to be used, as so:: information will require all interfaces to be used, as so::
>>> message['custom'] = 'bar' # Same as using message['custom']['custom'] >>> # Same as using message['custom']['custom']
>>> message['custom']['custom'] # Must use all interfaces >>> message['custom'] = 'bar'
>>> # Must use all interfaces
>>> message['custom']['custom']
'bar' 'bar'
If the plugin sets :attr:`is_extension` to ``True``, then both setting If the plugin sets :attr:`is_extension` to ``True``, then both setting
@ -272,8 +282,8 @@ class ElementBase(object):
""" """
#: The XML tag name of the element, not including any namespace #: The XML tag name of the element, not including any namespace
#: prefixes. For example, an :class:`ElementBase` object for ``<message />`` #: prefixes. For example, an :class:`ElementBase` object for
#: would use ``name = 'message'``. #: ``<message />`` would use ``name = 'message'``.
name = 'stanza' name = 'stanza'
#: The XML namespace for the element. Given ``<foo xmlns="bar" />``, #: The XML namespace for the element. Given ``<foo xmlns="bar" />``,
@ -522,8 +532,10 @@ class ElementBase(object):
if existing_xml is None: if existing_xml is None:
existing_xml = self.xml.find(plugin_class.tag_name()) existing_xml = self.xml.find(plugin_class.tag_name())
if existing_xml is not None and existing_xml.attrib.get('{%s}lang' % XML_NS, '') != lang:
existing_xml = None if existing_xml is not None:
if existing_xml.attrib.get('{%s}lang' % XML_NS, '') != lang:
existing_xml = None
plugin = plugin_class(parent=self, xml=existing_xml) plugin = plugin_class(parent=self, xml=existing_xml)
@ -761,13 +773,20 @@ class ElementBase(object):
else: else:
if attrib in self.sub_interfaces: if attrib in self.sub_interfaces:
if lang == '*': if lang == '*':
return self._set_all_sub_text(attrib, value, lang='*') return self._set_all_sub_text(attrib,
return self._set_sub_text(attrib, text=value, lang=lang) value,
lang='*')
return self._set_sub_text(attrib, text=value,
lang=lang)
elif attrib in self.bool_interfaces: elif attrib in self.bool_interfaces:
if value: if value:
return self._set_sub_text(attrib, '', keep=True, lang=lang) return self._set_sub_text(attrib, '',
keep=True,
lang=lang)
else: else:
return self._set_sub_text(attrib, '', keep=False, lang=lang) return self._set_sub_text(attrib, '',
keep=False,
lang=lang)
else: else:
self._set_attr(attrib, value) self._set_attr(attrib, value)
else: else:
@ -932,7 +951,8 @@ class ElementBase(object):
stanzas = self.xml.findall(name) stanzas = self.xml.findall(name)
if stanzas: if stanzas:
for stanza in stanzas: for stanza in stanzas:
stanza_lang = stanza.attrib.get('{%s}lang' % XML_NS, default_lang) stanza_lang = stanza.attrib.get('{%s}lang' % XML_NS,
default_lang)
if not lang or lang == '*' or stanza_lang == lang: if not lang or lang == '*' or stanza_lang == lang:
results[stanza_lang] = stanza.text results[stanza_lang] = stanza.text
return results return results
@ -996,7 +1016,9 @@ class ElementBase(object):
self._del_sub(name, lang) self._del_sub(name, lang)
for value_lang, value in values.items(): for value_lang, value in values.items():
if not lang or lang == '*' or value_lang == lang: if not lang or lang == '*' or value_lang == lang:
self._set_sub_text(name, text=value, keep=keep, lang=value_lang) self._set_sub_text(name, text=value,
keep=keep,
lang=value_lang)
def _del_sub(self, name, all=False, lang=None): def _del_sub(self, name, all=False, lang=None):
"""Remove sub elements that match the given name or XPath. """Remove sub elements that match the given name or XPath.
@ -1032,7 +1054,9 @@ class ElementBase(object):
not element.getchildren(): not element.getchildren():
# Only delete the originally requested elements, and # Only delete the originally requested elements, and
# any parent elements that have become empty. # any parent elements that have become empty.
if lang == '*' or element.attrib.get('{%s}lang' % XML_NS, default_lang) == lang: elem_lang = element.attrib.get('{%s}lang' % XML_NS,
default_lang)
if lang == '*' or elem_lang == lang:
parent.remove(element) parent.remove(element)
if not all: if not all:
# If we don't want to delete elements up the tree, stop # If we don't want to delete elements up the tree, stop
@ -1272,8 +1296,8 @@ class ElementBase(object):
return self return self
def _fix_ns(self, xpath, split=False, propagate_ns=True): def _fix_ns(self, xpath, split=False, propagate_ns=True):
return fix_ns(xpath, split=split, return fix_ns(xpath, split=split,
propagate_ns=propagate_ns, propagate_ns=propagate_ns,
default_ns=self.namespace) default_ns=self.namespace)
def __eq__(self, other): def __eq__(self, other):

View File

@ -55,7 +55,7 @@ RESPONSE_TIMEOUT = 30
WAIT_TIMEOUT = 0.1 WAIT_TIMEOUT = 0.1
#: The number of threads to use to handle XML stream events. This is not the #: The number of threads to use to handle XML stream events. This is not the
#: same as the number of custom event handling threads. #: same as the number of custom event handling threads.
#: :data:`HANDLER_THREADS` must be at least 1. For Python implementations #: :data:`HANDLER_THREADS` must be at least 1. For Python implementations
#: with a GIL, this should be left at 1, but for implemetnations without #: with a GIL, this should be left at 1, but for implemetnations without
#: a GIL increasing this value can provide better performance. #: a GIL increasing this value can provide better performance.
@ -124,7 +124,7 @@ class XMLStream(object):
self.ssl_support = SSL_SUPPORT self.ssl_support = SSL_SUPPORT
#: Most XMPP servers support TLSv1, but OpenFire in particular #: Most XMPP servers support TLSv1, but OpenFire in particular
#: does not work well with it. For OpenFire, set #: does not work well with it. For OpenFire, set
#: :attr:`ssl_version` to use ``SSLv23``:: #: :attr:`ssl_version` to use ``SSLv23``::
#: #:
#: import ssl #: import ssl
@ -134,30 +134,30 @@ class XMLStream(object):
#: Path to a file containing certificates for verifying the #: Path to a file containing certificates for verifying the
#: server SSL certificate. A non-``None`` value will trigger #: server SSL certificate. A non-``None`` value will trigger
#: certificate checking. #: certificate checking.
#: #:
#: .. note:: #: .. note::
#: #:
#: On Mac OS X, certificates in the system keyring will #: On Mac OS X, certificates in the system keyring will
#: be consulted, even if they are not in the provided file. #: be consulted, even if they are not in the provided file.
self.ca_certs = None self.ca_certs = None
#: The time in seconds to wait for events from the event queue, #: The time in seconds to wait for events from the event queue,
#: and also the time between checks for the process stop signal. #: and also the time between checks for the process stop signal.
self.wait_timeout = WAIT_TIMEOUT self.wait_timeout = WAIT_TIMEOUT
#: The time in seconds to wait before timing out waiting #: The time in seconds to wait before timing out waiting
#: for response stanzas. #: for response stanzas.
self.response_timeout = RESPONSE_TIMEOUT self.response_timeout = RESPONSE_TIMEOUT
#: The current amount to time to delay attempting to reconnect. #: The current amount to time to delay attempting to reconnect.
#: This value doubles (with some jitter) with each failed #: This value doubles (with some jitter) with each failed
#: connection attempt up to :attr:`reconnect_max_delay` seconds. #: connection attempt up to :attr:`reconnect_max_delay` seconds.
self.reconnect_delay = None self.reconnect_delay = None
#: Maximum time to delay between connection attempts is one hour. #: Maximum time to delay between connection attempts is one hour.
self.reconnect_max_delay = RECONNECT_MAX_DELAY self.reconnect_max_delay = RECONNECT_MAX_DELAY
#: Maximum number of attempts to connect to the server before #: Maximum number of attempts to connect to the server before
#: quitting and raising a 'connect_failed' event. Setting to #: quitting and raising a 'connect_failed' event. Setting to
#: ``None`` allows infinite reattempts, while setting it to ``0`` #: ``None`` allows infinite reattempts, while setting it to ``0``
#: will disable reconnection attempts. Defaults to ``None``. #: will disable reconnection attempts. Defaults to ``None``.
@ -178,16 +178,16 @@ class XMLStream(object):
#: The default port to return when querying DNS records. #: The default port to return when querying DNS records.
self.default_port = int(port) self.default_port = int(port)
#: The domain to try when querying DNS records. #: The domain to try when querying DNS records.
self.default_domain = '' self.default_domain = ''
#: The expected name of the server, for validation. #: The expected name of the server, for validation.
self._expected_server_name = '' self._expected_server_name = ''
#: The desired, or actual, address of the connected server. #: The desired, or actual, address of the connected server.
self.address = (host, int(port)) self.address = (host, int(port))
#: A file-like wrapper for the socket for use with the #: A file-like wrapper for the socket for use with the
#: :mod:`~xml.etree.ElementTree` module. #: :mod:`~xml.etree.ElementTree` module.
self.filesocket = None self.filesocket = None
@ -258,7 +258,7 @@ class XMLStream(object):
#: and data is sent immediately over the wire. #: and data is sent immediately over the wire.
self.session_started_event = threading.Event() self.session_started_event = threading.Event()
#: The default time in seconds to wait for a session to start #: The default time in seconds to wait for a session to start
#: after connecting before reconnecting and trying again. #: after connecting before reconnecting and trying again.
self.session_timeout = 45 self.session_timeout = 45
@ -417,12 +417,12 @@ class XMLStream(object):
if use_tls is not None: if use_tls is not None:
self.use_tls = use_tls self.use_tls = use_tls
# Repeatedly attempt to connect until a successful connection # Repeatedly attempt to connect until a successful connection
# is established. # is established.
attempts = self.reconnect_max_attempts attempts = self.reconnect_max_attempts
connected = self.state.transition('disconnected', 'connected', connected = self.state.transition('disconnected', 'connected',
func=self._connect, args=(reattempt,)) func=self._connect,
args=(reattempt,))
while reattempt and not connected and not self.stop.is_set(): while reattempt and not connected and not self.stop.is_set():
connected = self.state.transition('disconnected', 'connected', connected = self.state.transition('disconnected', 'connected',
func=self._connect) func=self._connect)
@ -437,7 +437,7 @@ class XMLStream(object):
def _connect(self, reattempt=True): def _connect(self, reattempt=True):
self.scheduler.remove('Session timeout check') self.scheduler.remove('Session timeout check')
self.stop.clear() self.stop.clear()
if self.reconnect_delay is None or not reattempt: if self.reconnect_delay is None or not reattempt:
delay = 1.0 delay = 1.0
else: else:
@ -483,7 +483,7 @@ class XMLStream(object):
if self.use_proxy: if self.use_proxy:
connected = self._connect_proxy() connected = self._connect_proxy()
if not connected: if not connected:
if reattempt: if reattempt:
self.reconnect_delay = delay self.reconnect_delay = delay
return False return False
@ -520,7 +520,8 @@ class XMLStream(object):
except (Socket.error, ssl.SSLError): except (Socket.error, ssl.SSLError):
log.error('CERT: Invalid certificate trust chain.') log.error('CERT: Invalid certificate trust chain.')
if not self.event_handled('ssl_invalid_chain'): if not self.event_handled('ssl_invalid_chain'):
self.disconnect(self.auto_reconnect, send_close=False) self.disconnect(self.auto_reconnect,
send_close=False)
else: else:
self.event('ssl_invalid_chain', direct=True) self.event('ssl_invalid_chain', direct=True)
return False return False
@ -528,7 +529,7 @@ class XMLStream(object):
self._der_cert = self.socket.getpeercert(binary_form=True) self._der_cert = self.socket.getpeercert(binary_form=True)
pem_cert = ssl.DER_cert_to_PEM_cert(self._der_cert) pem_cert = ssl.DER_cert_to_PEM_cert(self._der_cert)
log.debug('CERT: %s', pem_cert) log.debug('CERT: %s', pem_cert)
self.event('ssl_cert', pem_cert, direct=True) self.event('ssl_cert', pem_cert, direct=True)
try: try:
cert.verify(self._expected_server_name, self._der_cert) cert.verify(self._expected_server_name, self._der_cert)
@ -537,7 +538,9 @@ class XMLStream(object):
if not self.event_handled('ssl_invalid_cert'): if not self.event_handled('ssl_invalid_cert'):
self.disconnect(send_close=False) self.disconnect(send_close=False)
else: else:
self.event('ssl_invalid_cert', pem_cert, direct=True) self.event('ssl_invalid_cert',
pem_cert,
direct=True)
self.set_socket(self.socket, ignore=True) self.set_socket(self.socket, ignore=True)
#this event is where you should set your application state #this event is where you should set your application state
@ -630,7 +633,7 @@ class XMLStream(object):
If the disconnect should take place after all items If the disconnect should take place after all items
in the send queue have been sent, use ``wait=True``. in the send queue have been sent, use ``wait=True``.
.. warning:: .. warning::
If you are constantly adding items to the queue If you are constantly adding items to the queue
@ -651,7 +654,7 @@ class XMLStream(object):
""" """
self.state.transition('connected', 'disconnected', self.state.transition('connected', 'disconnected',
wait=2.0, wait=2.0,
func=self._disconnect, func=self._disconnect,
args=(reconnect, wait, send_close)) args=(reconnect, wait, send_close))
def _disconnect(self, reconnect=False, wait=None, send_close=True): def _disconnect(self, reconnect=False, wait=None, send_close=True):
@ -705,16 +708,18 @@ class XMLStream(object):
"""Reset the stream's state and reconnect to the server.""" """Reset the stream's state and reconnect to the server."""
log.debug("reconnecting...") log.debug("reconnecting...")
if self.state.ensure('connected'): if self.state.ensure('connected'):
self.state.transition('connected', 'disconnected', self.state.transition('connected', 'disconnected',
wait=2.0, wait=2.0,
func=self._disconnect, func=self._disconnect,
args=(True, wait, send_close)) args=(True, wait, send_close))
attempts = self.reconnect_max_attempts attempts = self.reconnect_max_attempts
log.debug("connecting...") log.debug("connecting...")
connected = self.state.transition('disconnected', 'connected', connected = self.state.transition('disconnected', 'connected',
wait=2.0, func=self._connect, args=(reattempt,)) wait=2.0,
func=self._connect,
args=(reattempt,))
while reattempt and not connected and not self.stop.is_set(): while reattempt and not connected and not self.stop.is_set():
connected = self.state.transition('disconnected', 'connected', connected = self.state.transition('disconnected', 'connected',
wait=2.0, func=self._connect) wait=2.0, func=self._connect)
@ -762,8 +767,8 @@ class XMLStream(object):
""" """
Configure and set options for a :class:`~dns.resolver.Resolver` Configure and set options for a :class:`~dns.resolver.Resolver`
instance, and other DNS related tasks. For example, you instance, and other DNS related tasks. For example, you
can also check :meth:`~socket.socket.getaddrinfo` to see can also check :meth:`~socket.socket.getaddrinfo` to see
if you need to call out to ``libresolv.so.2`` to if you need to call out to ``libresolv.so.2`` to
run ``res_init()``. run ``res_init()``.
Meant to be overridden. Meant to be overridden.
@ -817,7 +822,7 @@ class XMLStream(object):
log.debug('CERT: %s', pem_cert) log.debug('CERT: %s', pem_cert)
self.event('ssl_cert', pem_cert, direct=True) self.event('ssl_cert', pem_cert, direct=True)
try: try:
cert.verify(self._expected_server_name, self._der_cert) cert.verify(self._expected_server_name, self._der_cert)
except cert.CertificateError as err: except cert.CertificateError as err:
log.error(err.message) log.error(err.message)
@ -877,8 +882,8 @@ class XMLStream(object):
self.schedule('Whitespace Keepalive', self.schedule('Whitespace Keepalive',
self.whitespace_keepalive_interval, self.whitespace_keepalive_interval,
self.send_raw, self.send_raw,
args = (' ',), args=(' ',),
kwargs = {'now': True}, kwargs={'now': True},
repeat=True) repeat=True)
def _remove_schedules(self, event): def _remove_schedules(self, event):
@ -887,7 +892,7 @@ class XMLStream(object):
self.scheduler.remove('Certificate Expiration') self.scheduler.remove('Certificate Expiration')
def start_stream_handler(self, xml): def start_stream_handler(self, xml):
"""Perform any initialization actions, such as handshakes, """Perform any initialization actions, such as handshakes,
once the stream header has been sent. once the stream header has been sent.
Meant to be overridden. Meant to be overridden.
@ -895,8 +900,8 @@ class XMLStream(object):
pass pass
def register_stanza(self, stanza_class): def register_stanza(self, stanza_class):
"""Add a stanza object class as a known root stanza. """Add a stanza object class as a known root stanza.
A root stanza is one that appears as a direct child of the stream's A root stanza is one that appears as a direct child of the stream's
root element. root element.
@ -913,8 +918,8 @@ class XMLStream(object):
self.__root_stanza.append(stanza_class) self.__root_stanza.append(stanza_class)
def remove_stanza(self, stanza_class): def remove_stanza(self, stanza_class):
"""Remove a stanza from being a known root stanza. """Remove a stanza from being a known root stanza.
A root stanza is one that appears as a direct child of the stream's A root stanza is one that appears as a direct child of the stream's
root element. root element.
@ -979,8 +984,9 @@ class XMLStream(object):
"""Add a stream event handler that will be executed when a matching """Add a stream event handler that will be executed when a matching
stanza is received. stanza is received.
:param handler: The :class:`~sleekxmpp.xmlstream.handler.base.BaseHandler` :param handler:
derived object to execute. The :class:`~sleekxmpp.xmlstream.handler.base.BaseHandler`
derived object to execute.
""" """
if handler.stream is None: if handler.stream is None:
self.__handlers.append(handler) self.__handlers.append(handler)
@ -1007,11 +1013,12 @@ class XMLStream(object):
""" """
if port is None: if port is None:
port = self.default_port port = self.default_port
resolver = default_resolver() resolver = default_resolver()
self.configure_dns(resolver, domain=domain, port=port) self.configure_dns(resolver, domain=domain, port=port)
return resolve(domain, port, service=self.dns_service, resolver=resolver) return resolve(domain, port, service=self.dns_service,
resolver=resolver)
def pick_dns_answer(self, domain, port=None): def pick_dns_answer(self, domain, port=None):
"""Pick a server and port from DNS answers. """Pick a server and port from DNS answers.
@ -1029,7 +1036,7 @@ class XMLStream(object):
return self.dns_answers.next() return self.dns_answers.next()
else: else:
return next(self.dns_answers) return next(self.dns_answers)
def add_event_handler(self, name, pointer, def add_event_handler(self, name, pointer,
threaded=False, disposable=False): threaded=False, disposable=False):
"""Add a custom event handler that will be executed whenever """Add a custom event handler that will be executed whenever
@ -1144,9 +1151,9 @@ class XMLStream(object):
May optionally block until an expected response is received. May optionally block until an expected response is received.
:param data: The :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` :param data: The :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase`
stanza to send on the stream. stanza to send on the stream.
:param mask: **DEPRECATED** :param mask: **DEPRECATED**
An XML string snippet matching the structure An XML string snippet matching the structure
of the expected response. Execution will block of the expected response. Execution will block
in this thread until the response is received in this thread until the response is received
@ -1198,9 +1205,9 @@ class XMLStream(object):
"""Send an XML object on the stream, and optionally wait """Send an XML object on the stream, and optionally wait
for a response. for a response.
:param data: The :class:`~xml.etree.ElementTree.Element` XML object :param data: The :class:`~xml.etree.ElementTree.Element` XML object
to send on the stream. to send on the stream.
:param mask: **DEPRECATED** :param mask: **DEPRECATED**
An XML string snippet matching the structure An XML string snippet matching the structure
of the expected response. Execution will block of the expected response. Execution will block
in this thread until the response is received in this thread until the response is received
@ -1240,14 +1247,15 @@ class XMLStream(object):
count += 1 count += 1
except ssl.SSLError as serr: except ssl.SSLError as serr:
if tries >= self.ssl_retry_max: if tries >= self.ssl_retry_max:
log.debug('SSL error - max retries reached') log.debug('SSL error: max retries reached')
self.exception(serr) self.exception(serr)
log.warning("Failed to send %s", data) log.warning("Failed to send %s", data)
if reconnect is None: if reconnect is None:
reconnect = self.auto_reconnect reconnect = self.auto_reconnect
if not self.stop.is_set(): if not self.stop.is_set():
self.disconnect(reconnect, send_close=False) self.disconnect(reconnect,
log.warning('SSL write error - reattempting') send_close=False)
log.warning('SSL write error: retrying')
if not self.stop.is_set(): if not self.stop.is_set():
time.sleep(self.ssl_retry_delay) time.sleep(self.ssl_retry_delay)
tries += 1 tries += 1
@ -1302,7 +1310,7 @@ class XMLStream(object):
def _wait_for_threads(self): def _wait_for_threads(self):
with self.__thread_cond: with self.__thread_cond:
if self.__thread_count != 0: if self.__thread_count != 0:
log.debug("Waiting for %s threads to exit." % log.debug("Waiting for %s threads to exit." %
self.__thread_count) self.__thread_count)
name = threading.current_thread().name name = threading.current_thread().name
if name in self.__thread: if name in self.__thread:
@ -1334,7 +1342,7 @@ class XMLStream(object):
Defaults to ``True``. This does **not** mean that no Defaults to ``True``. This does **not** mean that no
threads are used at all if ``threaded=False``. threads are used at all if ``threaded=False``.
Regardless of these threading options, these threads will Regardless of these threading options, these threads will
always exist: always exist:
- The event queue processor - The event queue processor
@ -1424,7 +1432,7 @@ class XMLStream(object):
def __read_xml(self): def __read_xml(self):
"""Parse the incoming XML stream """Parse the incoming XML stream
Stream events are raised for each received stanza. Stream events are raised for each received stanza.
""" """
depth = 0 depth = 0
@ -1435,8 +1443,8 @@ class XMLStream(object):
# We have received the start of the root element. # We have received the start of the root element.
root = xml root = xml
log.debug('RECV: %s', tostring(root, xmlns=self.default_ns, log.debug('RECV: %s', tostring(root, xmlns=self.default_ns,
stream=self, stream=self,
top_level=True, top_level=True,
open_only=True)) open_only=True))
# Perform any stream initialization actions, such # Perform any stream initialization actions, such
# as handshakes. # as handshakes.
@ -1468,10 +1476,10 @@ class XMLStream(object):
"""Create a stanza object from a given XML object. """Create a stanza object from a given XML object.
If a specialized stanza type is not found for the XML, then If a specialized stanza type is not found for the XML, then
a generic :class:`~sleekxmpp.xmlstream.stanzabase.StanzaBase` a generic :class:`~sleekxmpp.xmlstream.stanzabase.StanzaBase`
stanza will be returned. stanza will be returned.
:param xml: The :class:`~xml.etree.ElementTree.Element` XML object :param xml: The :class:`~xml.etree.ElementTree.Element` XML object
to convert into a stanza object. to convert into a stanza object.
:param default_ns: Optional default namespace to use instead of the :param default_ns: Optional default namespace to use instead of the
stream's current default namespace. stream's current default namespace.
@ -1656,12 +1664,13 @@ class XMLStream(object):
count += 1 count += 1
except ssl.SSLError as serr: except ssl.SSLError as serr:
if tries >= self.ssl_retry_max: if tries >= self.ssl_retry_max:
log.debug('SSL error - max retries reached') log.debug('SSL error: max retries reached')
self.exception(serr) self.exception(serr)
log.warning("Failed to send %s", data) log.warning("Failed to send %s", data)
if not self.stop.is_set(): if not self.stop.is_set():
self.disconnect(self.auto_reconnect, send_close=False) self.disconnect(self.auto_reconnect,
log.warning('SSL write error - reattempting') send_close=False)
log.warning('SSL write error: retrying')
if not self.stop.is_set(): if not self.stop.is_set():
time.sleep(self.ssl_retry_delay) time.sleep(self.ssl_retry_delay)
tries += 1 tries += 1