fallback to disco if clients don't support caps. Fixes #4071

This commit is contained in:
Yann Leboulanger 2011-01-04 15:52:37 +01:00
parent b88162a198
commit ca0bcbb527
3 changed files with 70 additions and 28 deletions

View File

@ -75,14 +75,17 @@ def client_supports(client_caps, requested_feature):
else:
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,
caps_hash, hash_method combination.
"""
if not node or not caps_hash:
# improper caps, ignore client capabilities.
client_caps = NullClientCaps()
if fjid:
client_caps = NoClientCaps(fjid)
else:
# improper caps, ignore client capabilities.
client_caps = NullClientCaps()
elif not hash_method:
client_caps = OldClientCaps(caps_hash, node)
else:
@ -172,6 +175,7 @@ class AbstractClientCaps(object):
def __init__(self, caps_hash, node):
self._hash = caps_hash
self._node = node
self._hash_method = None
def get_discover_strategy(self):
return self._discover
@ -228,6 +232,7 @@ class OldClientCaps(AbstractClientCaps):
"""
def __init__(self, caps_hash, node):
AbstractClientCaps.__init__(self, caps_hash, node)
self._hash_method = 'old'
def _lookup_in_cache(self, caps_cache):
return caps_cache[('old', self._node + '#' + self._hash)]
@ -238,6 +243,22 @@ class OldClientCaps(AbstractClientCaps):
def _is_hash_valid(self, identities, features, dataforms):
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):
"""
@ -258,6 +279,7 @@ class NullClientCaps(AbstractClientCaps):
def __init__(self):
AbstractClientCaps.__init__(self, None, None)
self._hash_method = 'dummy'
def _lookup_in_cache(self, caps_cache):
# lookup something which does not exist to get a new CacheItem created
@ -341,14 +363,17 @@ class CapsCache(object):
def set_and_store(self, identities, features):
self.identities = identities
self.features = features
self._logger.add_caps_entry(self.hash_method, self.hash,
if self.hash_method != 'no':
self._logger.add_caps_entry(self.hash_method, self.hash,
identities, features)
self.status = CACHED
def update_last_seen(self):
if not self._recently_seen:
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):
"""
@ -401,3 +426,10 @@ class CapsCache(object):
discover(connection, jid)
else:
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]

View File

@ -660,7 +660,27 @@ class StreamConflictReceivedEvent(nec.NetworkIncomingEvent):
self.conn = self.base_event.conn
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'
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.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):
self.prio = self.stanza.getPriority()
try:
@ -690,15 +701,6 @@ class PresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
except Exception:
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):
self.conn = self.base_event.conn
self.stanza = self.base_event.stanza
@ -1489,7 +1491,8 @@ class PingErrorEvent(nec.NetworkIncomingEvent):
name = 'ping-error'
base_network_events = []
class CapsPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
class CapsPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent,
PresenceHelperEvent):
name = 'caps-presence-received'
base_network_events = ['raw-pres-received']
@ -1509,6 +1512,8 @@ class CapsPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
self.get_jid_resource()
except Exception:
return
self._generate_ptype()
self._generate_show()
self._extract_caps_from_presence()
return True

View File

@ -53,9 +53,14 @@ class ConnectionCaps(object):
if obj.conn.name != self._account:
return
obj.client_caps = self._create_suitable_client_caps(obj.node,
obj.caps_hash, obj.hash_method)
self._capscache.query_client_of_jid_if_unknown(self, obj.fjid,
obj.client_caps)
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.caps_hash, obj.hash_method)
else:
self._capscache.query_client_of_jid_if_unknown(self, obj.fjid,
obj.client_caps)
self._update_client_caps_of_contact(obj)
def _update_client_caps_of_contact(self, obj):