summaryrefslogtreecommitdiff
path: root/slixmpp
diff options
context:
space:
mode:
Diffstat (limited to 'slixmpp')
-rw-r--r--slixmpp/features/feature_mechanisms/mechanisms.py5
-rw-r--r--slixmpp/jid.py61
-rw-r--r--slixmpp/plugins/xep_0030/disco.py16
-rw-r--r--slixmpp/plugins/xep_0077/register.py2
-rw-r--r--slixmpp/plugins/xep_0153/vcard_avatar.py5
-rw-r--r--slixmpp/plugins/xep_0163.py10
-rw-r--r--slixmpp/plugins/xep_0199/ping.py5
-rw-r--r--slixmpp/plugins/xep_0223.py2
-rw-r--r--slixmpp/plugins/xep_0363/http_upload.py25
-rw-r--r--slixmpp/stanza/iq.py4
-rw-r--r--slixmpp/test/slixtest.py12
-rw-r--r--slixmpp/util/sasl/mechanisms.py6
-rw-r--r--slixmpp/version.py4
-rw-r--r--slixmpp/xmlstream/stanzabase.py14
-rw-r--r--slixmpp/xmlstream/tostring.py15
-rw-r--r--slixmpp/xmlstream/xmlstream.py22
16 files changed, 96 insertions, 112 deletions
diff --git a/slixmpp/features/feature_mechanisms/mechanisms.py b/slixmpp/features/feature_mechanisms/mechanisms.py
index 30449de0..26af1947 100644
--- a/slixmpp/features/feature_mechanisms/mechanisms.py
+++ b/slixmpp/features/feature_mechanisms/mechanisms.py
@@ -97,7 +97,10 @@ class FeatureMechanisms(BasePlugin):
jid = self.xmpp.requested_jid.bare
result[value] = creds.get('email', jid)
elif value == 'channel_binding':
- result[value] = self.xmpp.socket.get_channel_binding()
+ if isinstance(self.xmpp.socket, (ssl.SSLSocket, ssl.SSLObject)):
+ result[value] = self.xmpp.socket.get_channel_binding()
+ else:
+ result[value] = None
elif value == 'host':
result[value] = creds.get('host', self.xmpp.requested_jid.domain)
elif value == 'realm':
diff --git a/slixmpp/jid.py b/slixmpp/jid.py
index 9cb815db..dd6c1047 100644
--- a/slixmpp/jid.py
+++ b/slixmpp/jid.py
@@ -347,30 +347,10 @@ class JID:
return self._node
@property
- def user(self):
- return self._node
-
- @property
- def local(self):
- return self._node
-
- @property
- def username(self):
- return self._node
-
- @property
def domain(self):
return self._domain
@property
- def server(self):
- return self._domain
-
- @property
- def host(self):
- return self._domain
-
- @property
def resource(self):
return self._resource
@@ -382,45 +362,16 @@ class JID:
def full(self):
return self._full
- @property
- def jid(self):
- return self._full
-
@node.setter
def node(self, value):
self._node = _validate_node(value)
self._update_bare_full()
- @user.setter
- def user(self, value):
- self._node = _validate_node(value)
- self._update_bare_full()
-
- @local.setter
- def local(self, value):
- self._node = _validate_node(value)
- self._update_bare_full()
-
- @username.setter
- def username(self, value):
- self._node = _validate_node(value)
- self._update_bare_full()
-
@domain.setter
def domain(self, value):
self._domain = _validate_domain(value)
self._update_bare_full()
- @server.setter
- def server(self, value):
- self._domain = _validate_domain(value)
- self._update_bare_full()
-
- @host.setter
- def host(self, value):
- self._domain = _validate_domain(value)
- self._update_bare_full()
-
@bare.setter
def bare(self, value):
node, domain, resource = _parse_jid(value)
@@ -439,10 +390,14 @@ class JID:
self._node, self._domain, self._resource = _parse_jid(value)
self._update_bare_full()
- @jid.setter
- def jid(self, value):
- self._node, self._domain, self._resource = _parse_jid(value)
- self._update_bare_full()
+ user = node
+ local = node
+ username = node
+
+ server = domain
+ host = domain
+
+ jid = full
def __str__(self):
"""Use the full JID as the string value."""
diff --git a/slixmpp/plugins/xep_0030/disco.py b/slixmpp/plugins/xep_0030/disco.py
index ea9a33f4..59b1e0cc 100644
--- a/slixmpp/plugins/xep_0030/disco.py
+++ b/slixmpp/plugins/xep_0030/disco.py
@@ -299,23 +299,27 @@ class XEP_0030(BasePlugin):
return self.api['has_identity'](jid, node, ifrom, data)
async def get_info_from_domain(self, domain=None, timeout=None,
- cached=True, callback=None, **kwargs):
+ cached=True, callback=None):
if domain is None:
domain = self.xmpp.boundjid.domain
if not cached or domain not in self.domain_infos:
infos = [self.get_info(
- domain, timeout=timeout, **kwargs)]
+ domain, timeout=timeout)]
iq_items = await self.get_items(
- domain, timeout=timeout, **kwargs)
+ domain, timeout=timeout)
items = iq_items['disco_items']['items']
infos += [
- self.get_info(item[0], timeout=timeout, **kwargs)
+ self.get_info(item[0], timeout=timeout)
for item in items]
- info_futures, _ = await asyncio.wait(infos, timeout=timeout)
+ info_futures, _ = await asyncio.wait(
+ infos,
+ timeout=timeout,
+ loop=self.xmpp.loop
+ )
self.domain_infos[domain] = [
- future.result() for future in info_futures]
+ future.result() for future in info_futures if not future.exception()]
results = self.domain_infos[domain]
diff --git a/slixmpp/plugins/xep_0077/register.py b/slixmpp/plugins/xep_0077/register.py
index 8c0c6f09..a7c6780f 100644
--- a/slixmpp/plugins/xep_0077/register.py
+++ b/slixmpp/plugins/xep_0077/register.py
@@ -59,7 +59,7 @@ class XEP_0077(BasePlugin):
def _force_stream_feature(self, stanza):
if isinstance(stanza, StreamFeatures):
- if self.xmpp.use_tls or self.xmpp.use_ssl:
+ if not self.xmpp.disable_starttls:
if 'starttls' not in self.xmpp.features:
return stanza
elif not isinstance(self.xmpp.socket, ssl.SSLSocket):
diff --git a/slixmpp/plugins/xep_0153/vcard_avatar.py b/slixmpp/plugins/xep_0153/vcard_avatar.py
index 6430e8d6..cf10283a 100644
--- a/slixmpp/plugins/xep_0153/vcard_avatar.py
+++ b/slixmpp/plugins/xep_0153/vcard_avatar.py
@@ -167,10 +167,7 @@ class XEP_0153(BasePlugin):
data = pres['vcard_temp_update']['photo']
if data is None:
return
- elif data == '' or data != self.api['get_hash'](pres['from']):
- ifrom = pres['to'] if self.xmpp.is_component else None
- self.api['reset_hash'](pres['from'], ifrom=ifrom)
- self.xmpp.event('vcard_avatar_update', pres)
+ self.xmpp.event('vcard_avatar_update', pres)
# =================================================================
diff --git a/slixmpp/plugins/xep_0163.py b/slixmpp/plugins/xep_0163.py
index 047ca5d3..4c302efa 100644
--- a/slixmpp/plugins/xep_0163.py
+++ b/slixmpp/plugins/xep_0163.py
@@ -62,7 +62,10 @@ class XEP_0163(BasePlugin):
for ns in namespace:
self.xmpp['xep_0030'].add_feature('%s+notify' % ns,
jid=jid)
- asyncio.ensure_future(self.xmpp['xep_0115'].update_caps(jid))
+ asyncio.ensure_future(
+ self.xmpp['xep_0115'].update_caps(jid),
+ loop=self.xmpp.loop,
+ )
def remove_interest(self, namespace, jid=None):
"""
@@ -81,7 +84,10 @@ class XEP_0163(BasePlugin):
for ns in namespace:
self.xmpp['xep_0030'].del_feature(jid=jid,
feature='%s+notify' % namespace)
- asyncio.ensure_future(self.xmpp['xep_0115'].update_caps(jid))
+ asyncio.ensure_future(
+ self.xmpp['xep_0115'].update_caps(jid),
+ loop=self.xmpp.loop,
+ )
def publish(self, stanza, node=None, id=None, options=None, ifrom=None,
timeout_callback=None, callback=None, timeout=None):
diff --git a/slixmpp/plugins/xep_0199/ping.py b/slixmpp/plugins/xep_0199/ping.py
index 1153389b..f1070305 100644
--- a/slixmpp/plugins/xep_0199/ping.py
+++ b/slixmpp/plugins/xep_0199/ping.py
@@ -95,7 +95,10 @@ class XEP_0199(BasePlugin):
self.timeout = timeout
self.keepalive = True
- handler = lambda event=None: asyncio.ensure_future(self._keepalive(event))
+ handler = lambda event=None: asyncio.ensure_future(
+ self._keepalive(event),
+ loop=self.xmpp.loop,
+ )
self.xmpp.schedule('Ping keepalive',
self.interval,
handler,
diff --git a/slixmpp/plugins/xep_0223.py b/slixmpp/plugins/xep_0223.py
index 65d591f6..18875eee 100644
--- a/slixmpp/plugins/xep_0223.py
+++ b/slixmpp/plugins/xep_0223.py
@@ -26,7 +26,7 @@ class XEP_0223(BasePlugin):
dependencies = {'xep_0163', 'xep_0060', 'xep_0004'}
profile = {'pubsub#persist_items': True,
- 'pubsub#send_last_published_item': 'never'}
+ 'pubsub#access_model': 'whitelist'}
def configure(self, node, ifrom=None, callback=None, timeout=None):
"""
diff --git a/slixmpp/plugins/xep_0363/http_upload.py b/slixmpp/plugins/xep_0363/http_upload.py
index 65894975..266fc656 100644
--- a/slixmpp/plugins/xep_0363/http_upload.py
+++ b/slixmpp/plugins/xep_0363/http_upload.py
@@ -6,7 +6,6 @@
See the file LICENSE for copying permission.
"""
-import asyncio
import logging
import os.path
@@ -31,6 +30,10 @@ class UploadServiceNotFound(FileUploadError):
class FileTooBig(FileUploadError):
pass
+class HTTPError(FileUploadError):
+ def __str__(self):
+ return 'Could not upload file: %d (%s)' % (self.args[0], self.args[1])
+
class XEP_0363(BasePlugin):
''' This plugin only supports Python 3.5+ '''
@@ -68,12 +71,18 @@ class XEP_0363(BasePlugin):
def _handle_request(self, iq):
self.xmpp.event('http_upload_request', iq)
- async def find_upload_service(self, timeout=None):
- results = await self.xmpp['xep_0030'].get_info_from_domain()
+ async def find_upload_service(self, domain=None, timeout=None):
+ results = await self.xmpp['xep_0030'].get_info_from_domain(
+ domain=domain, timeout=timeout)
+ candidates = []
for info in results:
for identity in info['disco_info']['identities']:
if identity[0] == 'store' and identity[1] == 'file':
+ candidates.append(info)
+ for info in candidates:
+ for feature in info['disco_info']['features']:
+ if feature == Request.namespace:
return info
def request_slot(self, jid, filename, size, content_type=None, ifrom=None,
@@ -90,11 +99,12 @@ class XEP_0363(BasePlugin):
timeout_callback=timeout_callback)
async def upload_file(self, filename, size=None, content_type=None, *,
- input_file=None, ifrom=None, timeout=None,
+ input_file=None, ifrom=None, domain=None, timeout=None,
callback=None, timeout_callback=None):
''' Helper function which does all of the uploading process. '''
if self.upload_service is None:
- info_iq = await self.find_upload_service(timeout=timeout)
+ info_iq = await self.find_upload_service(
+ domain=domain, timeout=timeout)
if info_iq is None:
raise UploadServiceNotFound()
self.upload_service = info_iq['from']
@@ -125,7 +135,8 @@ class XEP_0363(BasePlugin):
basename = os.path.basename(filename)
slot_iq = await self.request_slot(self.upload_service, basename, size,
- content_type, ifrom, timeout)
+ content_type, ifrom, timeout,
+ timeout_callback=timeout_callback)
slot = slot_iq['http_upload_slot']
headers = {
@@ -141,6 +152,8 @@ class XEP_0363(BasePlugin):
data=input_file,
headers=headers,
timeout=timeout)
+ if response.status >= 400:
+ raise HTTPError(response.status, await response.text())
log.info('Response code: %d (%s)', response.status, await response.text())
response.close()
return slot['get']['url']
diff --git a/slixmpp/stanza/iq.py b/slixmpp/stanza/iq.py
index 385bbbd9..a3f16e2f 100644
--- a/slixmpp/stanza/iq.py
+++ b/slixmpp/stanza/iq.py
@@ -187,6 +187,10 @@ class Iq(RootStanza):
future = asyncio.Future()
+ # Prevents handlers from existing forever.
+ if timeout is None:
+ timeout = 120
+
def callback_success(result):
type_ = result['type']
if type_ == 'result':
diff --git a/slixmpp/test/slixtest.py b/slixmpp/test/slixtest.py
index b307b5c6..ff185368 100644
--- a/slixmpp/test/slixtest.py
+++ b/slixmpp/test/slixtest.py
@@ -222,7 +222,7 @@ class SlixTest(unittest.TestCase):
if Matcher is None:
raise ValueError("Unknown matching method.")
test = Matcher(criteria)
- self.failUnless(test.match(stanza),
+ self.assertTrue(test.match(stanza),
"Stanza did not match using %s method:\n" % method + \
"Criteria:\n%s\n" % str(criteria) + \
"Stanza:\n%s" % str(stanza))
@@ -280,7 +280,7 @@ class SlixTest(unittest.TestCase):
debug += "Generated stanza:\n%s\n" % highlight(tostring(stanza2.xml))
result = self.compare(xml, stanza.xml, stanza2.xml)
- self.failUnless(result, debug)
+ self.assertTrue(result, debug)
# ------------------------------------------------------------------
# Methods for simulating stanza streams.
@@ -487,7 +487,7 @@ class SlixTest(unittest.TestCase):
recv_xml.clear()
recv_xml.attrib = attrib
- self.failUnless(
+ self.assertTrue(
self.compare(xml, recv_xml),
"Stream headers do not match:\nDesired:\n%s\nReceived:\n%s" % (
'%s %s' % (xml.tag, xml.attrib),
@@ -543,7 +543,7 @@ class SlixTest(unittest.TestCase):
xml = self.parse_xml(header2)
sent_xml = self.parse_xml(sent_header2)
- self.failUnless(
+ self.assertTrue(
self.compare(xml, sent_xml),
"Stream headers do not match:\nDesired:\n%s\nSent:\n%s" % (
header, sent_header))
@@ -557,12 +557,12 @@ class SlixTest(unittest.TestCase):
if sent_data is None:
self.fail("No stanza was sent.")
if method == 'exact':
- self.failUnless(self.compare(xml, sent_xml),
+ self.assertTrue(self.compare(xml, sent_xml),
"Features do not match.\nDesired:\n%s\nReceived:\n%s" % (
highlight(tostring(xml)), highlight(tostring(sent_xml))))
elif method == 'mask':
matcher = MatchXMLMask(xml)
- self.failUnless(matcher.match(sent_xml),
+ self.assertTrue(matcher.match(sent_xml),
"Stanza did not match using %s method:\n" % method + \
"Criteria:\n%s\n" % highlight(tostring(xml)) + \
"Stanza:\n%s" % highlight(tostring(sent_xml)))
diff --git a/slixmpp/util/sasl/mechanisms.py b/slixmpp/util/sasl/mechanisms.py
index 36b2795c..874787a9 100644
--- a/slixmpp/util/sasl/mechanisms.py
+++ b/slixmpp/util/sasl/mechanisms.py
@@ -516,13 +516,13 @@ else:
def setup(self, name):
authzid = self.credentials['authzid']
if not authzid:
- authzid = 'xmpp@%s' % self.credentials['service-name']
+ authzid = 'xmpp@' + self.credentials['service-name'].decode()
_, self.gss = kerberos.authGSSClientInit(authzid)
self.step = 0
def process(self, challenge=b''):
- b64_challenge = b64encode(challenge)
+ b64_challenge = b64encode(challenge).decode('ascii')
try:
if self.step == 0:
result = kerberos.authGSSClientStep(self.gss, b64_challenge)
@@ -536,7 +536,7 @@ else:
kerberos.authGSSClientUnwrap(self.gss, b64_challenge)
resp = kerberos.authGSSClientResponse(self.gss)
- kerberos.authGSSClientWrap(self.gss, resp, username)
+ kerberos.authGSSClientWrap(self.gss, resp, username.decode())
resp = kerberos.authGSSClientResponse(self.gss)
except kerberos.GSSError as e:
diff --git a/slixmpp/version.py b/slixmpp/version.py
index a3d98366..4d767f1c 100644
--- a/slixmpp/version.py
+++ b/slixmpp/version.py
@@ -9,5 +9,5 @@
# We don't want to have to import the entire library
# just to get the version info for setup.py
-__version__ = '1.4.0'
-__version_info__ = (1, 4, 0)
+__version__ = '1.4.1'
+__version_info__ = (1, 4, 1)
diff --git a/slixmpp/xmlstream/stanzabase.py b/slixmpp/xmlstream/stanzabase.py
index 605dbb61..1c000b69 100644
--- a/slixmpp/xmlstream/stanzabase.py
+++ b/slixmpp/xmlstream/stanzabase.py
@@ -177,8 +177,9 @@ def fix_ns(xpath, split=False, propagate_ns=True, default_ns=''):
if '}' in ns_block:
# Apply the found namespace to following elements
# that do not have namespaces.
- namespace = ns_block.split('}')[0]
- elements = ns_block.split('}')[1].split('/')
+ ns_block_split = ns_block.split('}')
+ namespace = ns_block_split[0]
+ elements = ns_block_split[1].split('/')
else:
# Apply the stanza's namespace to the following
# elements since no namespace was provided.
@@ -1291,15 +1292,6 @@ class ElementBase(object):
def __bool__(self):
"""Stanza objects should be treated as True in boolean contexts.
-
- Python 3.x version.
- """
- return True
-
- def __nonzero__(self):
- """Stanza objects should be treated as True in boolean contexts.
-
- Python 2.x version.
"""
return True
diff --git a/slixmpp/xmlstream/tostring.py b/slixmpp/xmlstream/tostring.py
index 6726bf1e..d6cc85dd 100644
--- a/slixmpp/xmlstream/tostring.py
+++ b/slixmpp/xmlstream/tostring.py
@@ -45,11 +45,12 @@ def tostring(xml=None, xmlns='', stream=None, outbuffer='',
output = [outbuffer]
# Extract the element's tag name.
- tag_name = xml.tag.split('}', 1)[-1]
+ tag_split = xml.tag.split('}', 1)
+ tag_name = tag_split[-1]
# Extract the element's namespace if it is defined.
if '}' in xml.tag:
- tag_xmlns = xml.tag.split('}', 1)[0][1:]
+ tag_xmlns = tag_split[0][1:]
else:
tag_xmlns = ''
@@ -82,8 +83,9 @@ def tostring(xml=None, xmlns='', stream=None, outbuffer='',
if '}' not in attrib:
output.append(' %s="%s"' % (attrib, value))
else:
- attrib_ns = attrib.split('}')[0][1:]
- attrib = attrib.split('}')[1]
+ attrib_split = attrib.split('}')
+ attrib_ns = attrib_split[0][1:]
+ attrib = attrib_split[1]
if attrib_ns == XML_NS:
output.append(' xml:%s="%s"' % (attrib, value))
elif stream and attrib_ns in stream.namespace_map:
@@ -144,10 +146,7 @@ def escape(text, use_cdata=False):
'"': '"'}
if not use_cdata:
- text = list(text)
- for i, c in enumerate(text):
- text[i] = escapes.get(c, c)
- return ''.join(text)
+ return ''.join(escapes.get(c, c) for c in text)
else:
escape_needed = False
for c in text:
diff --git a/slixmpp/xmlstream/xmlstream.py b/slixmpp/xmlstream/xmlstream.py
index 0367db02..60557fff 100644
--- a/slixmpp/xmlstream/xmlstream.py
+++ b/slixmpp/xmlstream/xmlstream.py
@@ -285,7 +285,10 @@ class XMLStream(asyncio.BaseProtocol):
self.disable_starttls = disable_starttls
self.event("connecting")
- self._current_connection_attempt = asyncio.ensure_future(self._connect_routine())
+ self._current_connection_attempt = asyncio.ensure_future(
+ self._connect_routine(),
+ loop=self.loop,
+ )
async def _connect_routine(self):
self.event_when_connected = "connected"
@@ -306,7 +309,7 @@ class XMLStream(asyncio.BaseProtocol):
else:
ssl_context = None
- await asyncio.sleep(self.connect_loop_wait)
+ await asyncio.sleep(self.connect_loop_wait, loop=self.loop)
try:
await self.loop.create_connection(lambda: self,
self.address[0],
@@ -321,7 +324,10 @@ class XMLStream(asyncio.BaseProtocol):
log.debug('Connection failed: %s', e)
self.event("connection_failed", e)
self.connect_loop_wait = self.connect_loop_wait * 2 + 1
- self._current_connection_attempt = asyncio.ensure_future(self._connect_routine())
+ self._current_connection_attempt = asyncio.ensure_future(
+ self._connect_routine(),
+ loop=self.loop,
+ )
def process(self, *, forever=True, timeout=None):
"""Process all the available XMPP events (receiving or sending data on the
@@ -336,10 +342,10 @@ class XMLStream(asyncio.BaseProtocol):
else:
self.loop.run_until_complete(self.disconnected)
else:
- tasks = [asyncio.sleep(timeout)]
+ tasks = [asyncio.sleep(timeout, loop=self.loop)]
if not forever:
tasks.append(self.disconnected)
- self.loop.run_until_complete(asyncio.wait(tasks))
+ self.loop.run_until_complete(asyncio.wait(tasks, loop=self.loop))
def init_parser(self):
"""init the XML parser. The parser must always be reset for each new
@@ -781,7 +787,10 @@ class XMLStream(asyncio.BaseProtocol):
old_exception(e)
else:
self.exception(e)
- asyncio.ensure_future(handler_callback_routine(handler_callback))
+ asyncio.ensure_future(
+ handler_callback_routine(handler_callback),
+ loop=self.loop,
+ )
else:
try:
handler_callback(data)
@@ -995,4 +1004,3 @@ class XMLStream(asyncio.BaseProtocol):
:param exception: An unhandled exception object.
"""
pass
-