summaryrefslogtreecommitdiff
path: root/sleekxmpp/clientxmpp.py
diff options
context:
space:
mode:
Diffstat (limited to 'sleekxmpp/clientxmpp.py')
-rw-r--r--sleekxmpp/clientxmpp.py69
1 files changed, 48 insertions, 21 deletions
diff --git a/sleekxmpp/clientxmpp.py b/sleekxmpp/clientxmpp.py
index 20012b5f..590192db 100644
--- a/sleekxmpp/clientxmpp.py
+++ b/sleekxmpp/clientxmpp.py
@@ -15,22 +15,13 @@
from __future__ import absolute_import, unicode_literals
import logging
-import base64
-import sys
-import hashlib
-import random
-import threading
-
-import sleekxmpp
-from sleekxmpp import plugins
-from sleekxmpp import stanza
-from sleekxmpp import features
+
+from sleekxmpp.stanza import StreamFeatures
from sleekxmpp.basexmpp import BaseXMPP
-from sleekxmpp.stanza import *
-from sleekxmpp.xmlstream import XMLStream, RestartStream
-from sleekxmpp.xmlstream import StanzaBase, ET, register_stanza_plugin
-from sleekxmpp.xmlstream.matcher import *
-from sleekxmpp.xmlstream.handler import *
+from sleekxmpp.exceptions import XMPPError
+from sleekxmpp.xmlstream import XMLStream
+from sleekxmpp.xmlstream.matcher import MatchXPath
+from sleekxmpp.xmlstream.handler import Callback
# Flag indicating if DNS SRV records are available for use.
try:
@@ -74,12 +65,15 @@ class ClientXMPP(BaseXMPP):
BaseXMPP.__init__(self, jid, 'jabber:client')
self.set_jid(jid)
- self.password = password
self.escape_quotes = escape_quotes
self.plugin_config = plugin_config
self.plugin_whitelist = plugin_whitelist
self.default_port = 5222
+ self.credentials = {}
+
+ self.password = password
+
self.stream_header = "<stream:stream to='%s' %s %s version='1.0'>" % (
self.boundjid.host,
"xmlns:stream='%s'" % self.stream_ns,
@@ -97,6 +91,7 @@ class ClientXMPP(BaseXMPP):
self.bindfail = False
self.add_event_handler('connected', self._handle_connected)
+ self.add_event_handler('session_bind', self._handle_session_bind)
self.register_stanza(StreamFeatures)
@@ -117,6 +112,15 @@ class ClientXMPP(BaseXMPP):
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')
+
+ @property
+ def password(self):
+ return self.credentials.get('password', '')
+
+ @password.setter
+ def password(self, value):
+ self.credentials['password'] = value
def connect(self, address=tuple(), reattempt=True,
use_tls=True, use_ssl=False):
@@ -154,8 +158,10 @@ class ClientXMPP(BaseXMPP):
try:
record = "_xmpp-client._tcp.%s" % domain
answers = []
+ log.debug("Querying SRV records for %s" % domain)
for answer in dns.resolver.query(record, dns.rdatatype.SRV):
address = (answer.target.to_text()[:-1], answer.port)
+ log.debug("Found SRV record: %s", address)
answers.append((address, answer.priority, answer.weight))
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
log.warning("No SRV records for %s", domain)
@@ -167,7 +173,7 @@ class ClientXMPP(BaseXMPP):
return answers
else:
log.warning("dnspython is not installed -- " + \
- "relying on OS A record resolution")
+ "relying on OS A/AAAA record resolution")
return [((domain, port), 0, 0)]
def register_feature(self, name, handler, restart=False, order=5000):
@@ -236,10 +242,17 @@ class ClientXMPP(BaseXMPP):
iq = self.Iq()
iq['type'] = 'get'
iq.enable('roster')
+ 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, request=True)
+
response = iq.send(block, timeout, callback)
- if callback is None:
- return self._handle_roster(response, request=True)
+ if block:
+ self._handle_roster(response, request=True)
+ return response
def _handle_connected(self, event=None):
#TODO: Use stream state here
@@ -270,15 +283,22 @@ class ClientXMPP(BaseXMPP):
to a request for the roster, and not an
empty acknowledgement from the server.
"""
+ if iq['from'].bare and iq['from'].bare != self.boundjid.bare:
+ raise XMPPError(condition='service-unavailable')
if iq['type'] == 'set' or (iq['type'] == 'result' and request):
+ roster = self.client_roster
+ if iq['roster']['ver']:
+ roster.version = iq['roster']['ver']
for jid in iq['roster']['items']:
item = iq['roster']['items'][jid]
- roster = self.roster[iq['to'].bare]
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_received', iq)
self.event("roster_update", iq)
@@ -286,7 +306,14 @@ class ClientXMPP(BaseXMPP):
iq.reply()
iq.enable('roster')
iq.send()
- return True
+
+ def _handle_session_bind(self, jid):
+ """Set the client roster to the JID set by the server.
+
+ :param :class:`sleekxmpp.xmlstream.jid.JID` jid: The bound JID as
+ dictated by the server. The same as :attr:`boundjid`.
+ """
+ self.client_roster = self.roster[jid]
# To comply with PEP8, method names now use underscores.