summaryrefslogtreecommitdiff
path: root/sleekxmpp/clientxmpp.py
diff options
context:
space:
mode:
Diffstat (limited to 'sleekxmpp/clientxmpp.py')
-rw-r--r--sleekxmpp/clientxmpp.py79
1 files changed, 52 insertions, 27 deletions
diff --git a/sleekxmpp/clientxmpp.py b/sleekxmpp/clientxmpp.py
index 48637dad..8db6ef17 100644
--- a/sleekxmpp/clientxmpp.py
+++ b/sleekxmpp/clientxmpp.py
@@ -52,7 +52,6 @@ class ClientXMPP(BaseXMPP):
:param jid: The JID of the XMPP user account.
:param password: The password for the XMPP user account.
- :param ssl: **Deprecated.**
:param plugin_config: A dictionary of plugin configurations.
:param plugin_whitelist: A list of approved plugins that
will be loaded when calling
@@ -60,11 +59,15 @@ class ClientXMPP(BaseXMPP):
:param escape_quotes: **Deprecated.**
"""
- def __init__(self, jid, password, plugin_config={}, plugin_whitelist=[],
- escape_quotes=True, sasl_mech=None, lang='en'):
+ def __init__(self, jid, password, plugin_config=None, plugin_whitelist=None, escape_quotes=True, sasl_mech=None,
+ lang='en'):
+ if not plugin_whitelist:
+ plugin_whitelist = []
+ if not plugin_config:
+ plugin_config = {}
+
BaseXMPP.__init__(self, jid, 'jabber:client')
- self.set_jid(jid)
self.escape_quotes = escape_quotes
self.plugin_config = plugin_config
self.plugin_whitelist = plugin_whitelist
@@ -95,8 +98,9 @@ class ClientXMPP(BaseXMPP):
self.bound = False
self.bindfail = False
- self.add_event_handler('connected', self._handle_connected)
+ self.add_event_handler('connected', self._reset_connection_state)
self.add_event_handler('session_bind', self._handle_session_bind)
+ self.add_event_handler('roster_update', self._handle_roster)
self.register_stanza(StreamFeatures)
@@ -107,15 +111,18 @@ class ClientXMPP(BaseXMPP):
self.register_handler(
Callback('Roster Update',
StanzaPath('iq@type=set/roster'),
- self._handle_roster))
+ lambda iq: self.event('roster_update', iq)))
# Setup default stream features
self.register_plugin('feature_starttls')
self.register_plugin('feature_bind')
self.register_plugin('feature_session')
- self.register_plugin('feature_mechanisms',
- pconfig={'use_mech': sasl_mech} if sasl_mech else None)
self.register_plugin('feature_rosterver')
+ self.register_plugin('feature_preapproval')
+ self.register_plugin('feature_mechanisms')
+
+ if sasl_mech:
+ self['feature_mechanisms'].use_mech = sasl_mech
@property
def password(self):
@@ -133,7 +140,7 @@ class ClientXMPP(BaseXMPP):
be attempted. If that fails, the server user in the JID
will be used.
- :param address -- A tuple containing the server's host and port.
+ :param address: A tuple containing the server's host and port.
:param reattempt: If ``True``, repeat attempting to connect if an
error occurs. Defaults to ``True``.
:param use_tls: Indicates if TLS should be used for the
@@ -152,8 +159,6 @@ class ClientXMPP(BaseXMPP):
address = (self.boundjid.host, 5222)
self.dns_service = 'xmpp-client'
- self._expected_server_name = self.boundjid.host
-
return XMLStream.connect(self, address[0], address[1],
use_tls=use_tls, use_ssl=use_ssl,
reattempt=reattempt)
@@ -179,8 +184,7 @@ class ClientXMPP(BaseXMPP):
self._stream_feature_order.remove((order, name))
self._stream_feature_order.sort()
- def update_roster(self, jid, name=None, subscription=None, groups=[],
- block=True, timeout=None, callback=None):
+ def update_roster(self, jid, **kwargs):
"""Add or change a roster item.
:param jid: The JID of the entry to modify.
@@ -201,6 +205,16 @@ class ClientXMPP(BaseXMPP):
Will be executed when the roster is received.
Implies ``block=False``.
"""
+ current = self.client_roster[jid]
+
+ name = kwargs.get('name', current['name'])
+ subscription = kwargs.get('subscription', current['subscription'])
+ groups = kwargs.get('groups', current['groups'])
+
+ block = kwargs.get('block', True)
+ timeout = kwargs.get('timeout', None)
+ callback = kwargs.get('callback', None)
+
return self.client_roster.update(jid, name, subscription, groups,
block, timeout, callback)
@@ -233,17 +247,25 @@ class ClientXMPP(BaseXMPP):
if 'rosterver' in self.features:
iq['roster']['ver'] = self.client_roster.version
- if not block and callback is None:
- callback = lambda resp: self._handle_roster(resp)
+
+ if not block or callback is not None:
+ block = False
+ if callback is None:
+ callback = lambda resp: self.event('roster_update', resp)
+ else:
+ orig_cb = callback
+ def wrapped(resp):
+ self.event('roster_update', resp)
+ orig_cb(resp)
+ callback = wrapped
response = iq.send(block, timeout, callback)
- self.event('roster_received', response)
if block:
- self._handle_roster(response)
+ self.event('roster_update', response)
return response
- def _handle_connected(self, event=None):
+ def _reset_connection_state(self, event=None):
#TODO: Use stream state here
self.authenticated = False
self.sessionstarted = False
@@ -263,6 +285,8 @@ class ClientXMPP(BaseXMPP):
# Don't continue if the feature requires
# restarting the XML stream.
return True
+ log.debug('Finished processing stream features.')
+ self.event('stream_negotiated')
def _handle_roster(self, iq):
"""Update the roster after receiving a roster stanza.
@@ -277,17 +301,18 @@ class ClientXMPP(BaseXMPP):
if iq['roster']['ver']:
roster.version = iq['roster']['ver']
items = iq['roster']['items']
- for jid in items:
- item = items[jid]
- roster[jid]['name'] = item['name']
- roster[jid]['groups'] = item['groups']
- roster[jid]['from'] = item['subscription'] in ['from', 'both']
- roster[jid]['to'] = item['subscription'] in ['to', 'both']
- roster[jid]['pending_out'] = (item['ask'] == 'subscribe')
- roster[jid].save(remove=(item['subscription'] == 'remove'))
+ valid_subscriptions = ('to', 'from', 'both', 'none', 'remove')
+ for jid, item in items.items():
+ if item['subscription'] in valid_subscriptions:
+ roster[jid]['name'] = item['name']
+ roster[jid]['groups'] = item['groups']
+ roster[jid]['from'] = item['subscription'] in ('from', 'both')
+ roster[jid]['to'] = item['subscription'] in ('to', 'both')
+ roster[jid]['pending_out'] = (item['ask'] == 'subscribe')
+
+ roster[jid].save(remove=(item['subscription'] == 'remove'))
- self.event("roster_update", iq)
if iq['type'] == 'set':
resp = self.Iq(stype='result',
sto=iq['from'],