fallback to disco if clients don't support caps. Fixes #4071
This commit is contained in:
parent
b88162a198
commit
ca0bcbb527
|
@ -75,12 +75,15 @@ def client_supports(client_caps, requested_feature):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def create_suitable_client_caps(node, caps_hash, hash_method):
|
def create_suitable_client_caps(node, caps_hash, hash_method, fjid=None):
|
||||||
"""
|
"""
|
||||||
Create and return a suitable ClientCaps object for the given node,
|
Create and return a suitable ClientCaps object for the given node,
|
||||||
caps_hash, hash_method combination.
|
caps_hash, hash_method combination.
|
||||||
"""
|
"""
|
||||||
if not node or not caps_hash:
|
if not node or not caps_hash:
|
||||||
|
if fjid:
|
||||||
|
client_caps = NoClientCaps(fjid)
|
||||||
|
else:
|
||||||
# improper caps, ignore client capabilities.
|
# improper caps, ignore client capabilities.
|
||||||
client_caps = NullClientCaps()
|
client_caps = NullClientCaps()
|
||||||
elif not hash_method:
|
elif not hash_method:
|
||||||
|
@ -172,6 +175,7 @@ class AbstractClientCaps(object):
|
||||||
def __init__(self, caps_hash, node):
|
def __init__(self, caps_hash, node):
|
||||||
self._hash = caps_hash
|
self._hash = caps_hash
|
||||||
self._node = node
|
self._node = node
|
||||||
|
self._hash_method = None
|
||||||
|
|
||||||
def get_discover_strategy(self):
|
def get_discover_strategy(self):
|
||||||
return self._discover
|
return self._discover
|
||||||
|
@ -228,6 +232,7 @@ class OldClientCaps(AbstractClientCaps):
|
||||||
"""
|
"""
|
||||||
def __init__(self, caps_hash, node):
|
def __init__(self, caps_hash, node):
|
||||||
AbstractClientCaps.__init__(self, caps_hash, node)
|
AbstractClientCaps.__init__(self, caps_hash, node)
|
||||||
|
self._hash_method = 'old'
|
||||||
|
|
||||||
def _lookup_in_cache(self, caps_cache):
|
def _lookup_in_cache(self, caps_cache):
|
||||||
return caps_cache[('old', self._node + '#' + self._hash)]
|
return caps_cache[('old', self._node + '#' + self._hash)]
|
||||||
|
@ -238,6 +243,22 @@ class OldClientCaps(AbstractClientCaps):
|
||||||
def _is_hash_valid(self, identities, features, dataforms):
|
def _is_hash_valid(self, identities, features, dataforms):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
class NoClientCaps(AbstractClientCaps):
|
||||||
|
"""
|
||||||
|
For clients that don't support XEP-0115
|
||||||
|
"""
|
||||||
|
def __init__(self, fjid):
|
||||||
|
AbstractClientCaps.__init__(self, fjid, fjid)
|
||||||
|
self._hash_method = 'no'
|
||||||
|
|
||||||
|
def _lookup_in_cache(self, caps_cache):
|
||||||
|
return caps_cache[('no', self._node)]
|
||||||
|
|
||||||
|
def _discover(self, connection, jid):
|
||||||
|
connection.discoverInfo(jid)
|
||||||
|
|
||||||
|
def _is_hash_valid(self, identities, features, dataforms):
|
||||||
|
return True
|
||||||
|
|
||||||
class NullClientCaps(AbstractClientCaps):
|
class NullClientCaps(AbstractClientCaps):
|
||||||
"""
|
"""
|
||||||
|
@ -258,6 +279,7 @@ class NullClientCaps(AbstractClientCaps):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
AbstractClientCaps.__init__(self, None, None)
|
AbstractClientCaps.__init__(self, None, None)
|
||||||
|
self._hash_method = 'dummy'
|
||||||
|
|
||||||
def _lookup_in_cache(self, caps_cache):
|
def _lookup_in_cache(self, caps_cache):
|
||||||
# lookup something which does not exist to get a new CacheItem created
|
# lookup something which does not exist to get a new CacheItem created
|
||||||
|
@ -341,6 +363,7 @@ class CapsCache(object):
|
||||||
def set_and_store(self, identities, features):
|
def set_and_store(self, identities, features):
|
||||||
self.identities = identities
|
self.identities = identities
|
||||||
self.features = features
|
self.features = features
|
||||||
|
if self.hash_method != 'no':
|
||||||
self._logger.add_caps_entry(self.hash_method, self.hash,
|
self._logger.add_caps_entry(self.hash_method, self.hash,
|
||||||
identities, features)
|
identities, features)
|
||||||
self.status = CACHED
|
self.status = CACHED
|
||||||
|
@ -348,7 +371,9 @@ class CapsCache(object):
|
||||||
def update_last_seen(self):
|
def update_last_seen(self):
|
||||||
if not self._recently_seen:
|
if not self._recently_seen:
|
||||||
self._recently_seen = True
|
self._recently_seen = True
|
||||||
self._logger.update_caps_time(self.hash_method, self.hash)
|
if self.hash_method != 'no':
|
||||||
|
self._logger.update_caps_time(self.hash_method,
|
||||||
|
self.hash)
|
||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
"""
|
"""
|
||||||
|
@ -401,3 +426,10 @@ class CapsCache(object):
|
||||||
discover(connection, jid)
|
discover(connection, jid)
|
||||||
else:
|
else:
|
||||||
q.update_last_seen()
|
q.update_last_seen()
|
||||||
|
|
||||||
|
def forget_caps(self, client_caps):
|
||||||
|
hash_method = client_caps._hash_method
|
||||||
|
hash = client_caps._hash
|
||||||
|
key = (hash_method, hash)
|
||||||
|
if key in self.__cache:
|
||||||
|
del self.__cache[key]
|
||||||
|
|
|
@ -660,7 +660,27 @@ class StreamConflictReceivedEvent(nec.NetworkIncomingEvent):
|
||||||
self.conn = self.base_event.conn
|
self.conn = self.base_event.conn
|
||||||
return True
|
return True
|
||||||
|
|
||||||
class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
class PresenceHelperEvent:
|
||||||
|
def _generate_show(self):
|
||||||
|
self.show = self.stanza.getShow()
|
||||||
|
if self.show not in ('chat', 'away', 'xa', 'dnd'):
|
||||||
|
self.show = '' # We ignore unknown show
|
||||||
|
if not self.ptype and not self.show:
|
||||||
|
self.show = 'online'
|
||||||
|
elif self.ptype == 'unavailable':
|
||||||
|
self.show = 'offline'
|
||||||
|
|
||||||
|
def _generate_ptype(self):
|
||||||
|
self.ptype = self.stanza.getType()
|
||||||
|
if self.ptype == 'available':
|
||||||
|
self.ptype = None
|
||||||
|
rfc_types = ('unavailable', 'error', 'subscribe', 'subscribed',
|
||||||
|
'unsubscribe', 'unsubscribed')
|
||||||
|
if self.ptype and not self.ptype in rfc_types:
|
||||||
|
self.ptype = None
|
||||||
|
|
||||||
|
class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent,
|
||||||
|
PresenceHelperEvent):
|
||||||
name = 'presence-received'
|
name = 'presence-received'
|
||||||
base_network_events = ['raw-pres-received']
|
base_network_events = ['raw-pres-received']
|
||||||
|
|
||||||
|
@ -674,15 +694,6 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||||
self.keyID = helpers.prepare_and_validate_gpg_keyID(self.conn.name,
|
self.keyID = helpers.prepare_and_validate_gpg_keyID(self.conn.name,
|
||||||
self.jid, self.keyID)
|
self.jid, self.keyID)
|
||||||
|
|
||||||
def _generate_show(self):
|
|
||||||
self.show = self.stanza.getShow()
|
|
||||||
if self.show not in ('chat', 'away', 'xa', 'dnd'):
|
|
||||||
self.show = '' # We ignore unknown show
|
|
||||||
if not self.ptype and not self.show:
|
|
||||||
self.show = 'online'
|
|
||||||
elif self.ptype == 'unavailable':
|
|
||||||
self.show = 'offline'
|
|
||||||
|
|
||||||
def _generate_prio(self):
|
def _generate_prio(self):
|
||||||
self.prio = self.stanza.getPriority()
|
self.prio = self.stanza.getPriority()
|
||||||
try:
|
try:
|
||||||
|
@ -690,15 +701,6 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||||
except Exception:
|
except Exception:
|
||||||
self.prio = 0
|
self.prio = 0
|
||||||
|
|
||||||
def _generate_ptype(self):
|
|
||||||
self.ptype = self.stanza.getType()
|
|
||||||
if self.ptype == 'available':
|
|
||||||
self.ptype = None
|
|
||||||
rfc_types = ('unavailable', 'error', 'subscribe', 'subscribed',
|
|
||||||
'unsubscribe', 'unsubscribed')
|
|
||||||
if self.ptype and not self.ptype in rfc_types:
|
|
||||||
self.ptype = None
|
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.conn = self.base_event.conn
|
self.conn = self.base_event.conn
|
||||||
self.stanza = self.base_event.stanza
|
self.stanza = self.base_event.stanza
|
||||||
|
@ -1489,7 +1491,8 @@ class PingErrorEvent(nec.NetworkIncomingEvent):
|
||||||
name = 'ping-error'
|
name = 'ping-error'
|
||||||
base_network_events = []
|
base_network_events = []
|
||||||
|
|
||||||
class CapsPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
class CapsPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent,
|
||||||
|
PresenceHelperEvent):
|
||||||
name = 'caps-presence-received'
|
name = 'caps-presence-received'
|
||||||
base_network_events = ['raw-pres-received']
|
base_network_events = ['raw-pres-received']
|
||||||
|
|
||||||
|
@ -1509,6 +1512,8 @@ class CapsPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
|
||||||
self.get_jid_resource()
|
self.get_jid_resource()
|
||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
|
self._generate_ptype()
|
||||||
|
self._generate_show()
|
||||||
self._extract_caps_from_presence()
|
self._extract_caps_from_presence()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,13 @@ class ConnectionCaps(object):
|
||||||
def _nec_caps_presence_received(self, obj):
|
def _nec_caps_presence_received(self, obj):
|
||||||
if obj.conn.name != self._account:
|
if obj.conn.name != self._account:
|
||||||
return
|
return
|
||||||
|
obj.client_caps = self._create_suitable_client_caps(obj.node,
|
||||||
|
obj.caps_hash, obj.hash_method, obj.fjid)
|
||||||
|
if obj.show == 'offline' and obj.client_caps._hash_method == 'no':
|
||||||
|
self._capscache.forget_caps(obj.client_caps)
|
||||||
obj.client_caps = self._create_suitable_client_caps(obj.node,
|
obj.client_caps = self._create_suitable_client_caps(obj.node,
|
||||||
obj.caps_hash, obj.hash_method)
|
obj.caps_hash, obj.hash_method)
|
||||||
|
else:
|
||||||
self._capscache.query_client_of_jid_if_unknown(self, obj.fjid,
|
self._capscache.query_client_of_jid_if_unknown(self, obj.fjid,
|
||||||
obj.client_caps)
|
obj.client_caps)
|
||||||
self._update_client_caps_of_contact(obj)
|
self._update_client_caps_of_contact(obj)
|
||||||
|
|
Loading…
Reference in New Issue