Swtich from old to new caps API.

Now we do:

contact.supports(feauture) instead of gajim.capscache.is_supported(contact, feature)
This commit is contained in:
Stephan Erb 2009-10-27 22:41:39 +01:00
parent c7ff97703f
commit 33fe53ff7d
9 changed files with 84 additions and 109 deletions

View File

@ -1333,9 +1333,7 @@ class ChatControl(ChatControlBase):
def update_toolbar(self): def update_toolbar(self):
# Formatting # Formatting
if gajim.capscache.is_supported(self.contact, NS_XHTML_IM) \ if self.contact.supports(NS_XHTML_IM) and not self.gpg_is_active:
and not gajim.capscache.is_supported(self.contact, 'notexistant') \
and not self.gpg_is_active:
self._formattings_button.set_sensitive(True) self._formattings_button.set_sensitive(True)
else: else:
self._formattings_button.set_sensitive(False) self._formattings_button.set_sensitive(False)
@ -1348,12 +1346,11 @@ class ChatControl(ChatControlBase):
self._add_to_roster_button.hide() self._add_to_roster_button.hide()
# Send file # Send file
if gajim.capscache.is_supported(self.contact, NS_FILE) and \ if self.contact.supports(NS_FILE) and self.contact.resource:
self.contact.resource:
self._send_file_button.set_sensitive(True) self._send_file_button.set_sensitive(True)
else: else:
self._send_file_button.set_sensitive(False) self._send_file_button.set_sensitive(False)
if not gajim.capscache.is_supported(self.contact, NS_FILE): if not self.contact.supports(NS_FILE):
self._send_file_button.set_tooltip_text(_( self._send_file_button.set_tooltip_text(_(
"This contact does not support file transfer.")) "This contact does not support file transfer."))
else: else:
@ -1362,7 +1359,7 @@ class ChatControl(ChatControlBase):
"her a file.")) "her a file."))
# Convert to GC # Convert to GC
if gajim.capscache.is_supported(self.contact, NS_MUC): if self.contact.supports(NS_MUC):
self._convert_to_gc_button.set_sensitive(True) self._convert_to_gc_button.set_sensitive(True)
else: else:
self._convert_to_gc_button.set_sensitive(False) self._convert_to_gc_button.set_sensitive(False)
@ -1828,9 +1825,7 @@ class ChatControl(ChatControlBase):
def _on_sent(id_, contact, message, encrypted, xhtml): def _on_sent(id_, contact, message, encrypted, xhtml):
# XXX: Once we have fallback to disco, remove notexistant check # XXX: Once we have fallback to disco, remove notexistant check
if gajim.capscache.is_supported(contact, NS_RECEIPTS) \ if contact.supports(NS_RECEIPTS) and gajim.config.get_per('accounts',
and not gajim.capscache.is_supported(contact,
'notexistant') and gajim.config.get_per('accounts',
self.account, 'request_receipt'): self.account, 'request_receipt'):
xep0184_id = id_ xep0184_id = id_
else: else:
@ -2137,10 +2132,7 @@ class ChatControl(ChatControlBase):
toggle_gpg_menuitem.set_active(self.gpg_is_active) toggle_gpg_menuitem.set_active(self.gpg_is_active)
# disable esessions if we or the other client don't support them # disable esessions if we or the other client don't support them
# XXX: Once we have fallback to disco, remove notexistant check if not gajim.HAVE_PYCRYPTO or not contact.supports(NS_ESESSION) or \
if not gajim.HAVE_PYCRYPTO or \
not gajim.capscache.is_supported(contact, NS_ESESSION) or \
gajim.capscache.is_supported(contact, 'notexistant') or \
not gajim.config.get_per('accounts', self.account, 'enable_esessions'): not gajim.config.get_per('accounts', self.account, 'enable_esessions'):
toggle_e2e_menuitem.set_sensitive(False) toggle_e2e_menuitem.set_sensitive(False)
else: else:
@ -2152,13 +2144,13 @@ class ChatControl(ChatControlBase):
add_to_roster_menuitem.show() add_to_roster_menuitem.show()
# check if it's possible to send a file # check if it's possible to send a file
if gajim.capscache.is_supported(contact, NS_FILE): if contact.supports(NS_FILE):
send_file_menuitem.set_sensitive(True) send_file_menuitem.set_sensitive(True)
else: else:
send_file_menuitem.set_sensitive(False) send_file_menuitem.set_sensitive(False)
# check if it's possible to convert to groupchat # check if it's possible to convert to groupchat
if gajim.capscache.is_supported(contact, NS_MUC): if contact.supports(NS_MUC):
convert_to_gc_menuitem.set_sensitive(True) convert_to_gc_menuitem.set_sensitive(True)
else: else:
convert_to_gc_menuitem.set_sensitive(False) convert_to_gc_menuitem.set_sensitive(False)
@ -2471,12 +2463,8 @@ class ChatControl(ChatControlBase):
want_e2e = not e2e_is_active and not self.gpg_is_active \ want_e2e = not e2e_is_active and not self.gpg_is_active \
and e2e_pref and e2e_pref
# XXX: Once we have fallback to disco, remove notexistant check
if want_e2e and not self.no_autonegotiation \ if want_e2e and not self.no_autonegotiation \
and gajim.HAVE_PYCRYPTO \ and gajim.HAVE_PYCRYPTO and self.contact.supports(NS_ESESSION):
and gajim.capscache.is_supported(self.contact,
NS_ESESSION) and not gajim.capscache.is_supported(
self.contact, 'notexistant'):
self.begin_e2e_negotiation() self.begin_e2e_negotiation()
else: else:
self.send_chatstate('active', self.contact) self.send_chatstate('active', self.contact)

View File

@ -65,8 +65,14 @@ class AbstractClientCaps(object):
def _lookup_in_cache(self, caps_cache): def _lookup_in_cache(self, caps_cache):
''' To be implemented by subclassess ''' ''' To be implemented by subclassess '''
raise NotImplementedError() raise NotImplementedError()
def get_hash_validation_strategy(self):
return self._is_hash_valid
def _is_hash_valid(self, identities, features, dataforms):
raise NotImplementedError()
class ClientCaps(AbstractClientCaps): class ClientCaps(AbstractClientCaps):
''' The current XEP-115 implementation ''' ''' The current XEP-115 implementation '''
@ -81,6 +87,11 @@ class ClientCaps(AbstractClientCaps):
def _discover(self, connection, jid): def _discover(self, connection, jid):
connection.discoverInfo(jid, '%s#%s' % (self._node, self._hash)) connection.discoverInfo(jid, '%s#%s' % (self._node, self._hash))
def _is_hash_valid(self, identities, features, dataforms):
computed_hash = helpers.compute_caps_hash(identities, features,
dataforms=dataforms, hash_method=self._hash_method)
return computed_hash == self._hash
class OldClientCaps(AbstractClientCaps): class OldClientCaps(AbstractClientCaps):
''' Old XEP-115 implemtation. Kept around for background competability. ''' ''' Old XEP-115 implemtation. Kept around for background competability. '''
@ -94,6 +105,8 @@ class OldClientCaps(AbstractClientCaps):
def _discover(self, connection, jid): def _discover(self, connection, jid):
connection.discoverInfo(jid) connection.discoverInfo(jid)
def _is_hash_valid(self, identities, features, dataforms):
return True
class NullClientCaps(AbstractClientCaps): class NullClientCaps(AbstractClientCaps):
''' '''
@ -112,6 +125,8 @@ class NullClientCaps(AbstractClientCaps):
def _discover(self, connection, jid): def _discover(self, connection, jid):
pass pass
def _is_hash_valid(self, identities, features, dataforms):
return False
class CapsCache(object): class CapsCache(object):
''' '''
@ -238,11 +253,17 @@ class CapsCache(object):
gajim.capscache = CapsCache(gajim.logger) gajim.capscache = CapsCache(gajim.logger)
class ConnectionCaps(object): class ConnectionCaps(object):
''' This class highly depends on that it is a part of Connection class. ''' '''
This class highly depends on that it is a part of Connection class.
'''
def _capsPresenceCB(self, con, presence): def _capsPresenceCB(self, con, presence):
''' Handle incoming presence stanzas... This is a callback '''
for xmpp registered in connection_handlers.py''' Handle incoming presence stanzas... This is a callback for xmpp
registered in connection_handlers.py
'''
# we will put these into proper Contact object and ask # we will put these into proper Contact object and ask
# for disco... so that disco will learn how to interpret # for disco... so that disco will learn how to interpret
@ -264,64 +285,47 @@ class ConnectionCaps(object):
# into Contacts # into Contacts
return return
# get the caps element caps_tag = presence.getTag('c')
caps = presence.getTag('c') if not caps_tag:
if not caps: # presence did not contain caps_tag
contact.caps_node = None client_caps = NullClientCaps()
contact.caps_hash = None else:
contact.caps_hash_method = None hash_method, node, caps_hash = caps_tag['hash'], caps_tag['node'], caps_tag['ver']
return
hash_method, node, hash_ = caps['hash'], caps['node'], caps['ver'] if node is None or caps_hash is None:
# improper caps in stanza, ignore client capabilities.
client_caps = NullClientCaps()
elif hash_method is None:
client_caps = OldClientCaps(caps_hash, node)
else:
client_caps = ClientCaps(caps_hash, node, hash_method)
gajim.capscache.query_client_of_jid_if_unknown(self, jid, client_caps)
contact.client_caps = client_caps
if hash_method is None and node and hash_:
# Old XEP-115 implentation
hash_method = 'old'
if hash_method is None or node is None or hash_ is None:
# improper caps in stanza, ignoring
contact.caps_node = None
contact.caps_hash = None
contact.hash_method = None
return
# start disco query...
gajim.capscache.preload(self, jid, node, hash_method, hash_)
# overwriting old data
contact.caps_node = node
contact.caps_hash_method = hash_method
contact.caps_hash = hash_
if pm_ctrl: if pm_ctrl:
pm_ctrl.update_contact() pm_ctrl.update_contact()
def _capsDiscoCB(self, jid, node, identities, features, dataforms): def _capsDiscoCB(self, jid, node, identities, features, dataforms):
contact = gajim.contacts.get_contact_from_full_jid(self.name, jid) contact = gajim.contacts.get_contact_from_full_jid(self.name, jid)
if not contact: if not contact:
room_jid, nick = gajim.get_room_and_nick_from_fjid(jid) room_jid, nick = gajim.get_room_and_nick_from_fjid(jid)
contact = gajim.contacts.get_gc_contact(self.name, room_jid, nick) contact = gajim.contacts.get_gc_contact(self.name, room_jid, nick)
if contact is None: if contact is None:
return return
if not contact.caps_node:
return # we didn't asked for that?
if contact.caps_hash_method != 'old':
computed_hash = helpers.compute_caps_hash(identities, features,
dataforms=dataforms, hash_method=contact.caps_hash_method)
if computed_hash != contact.caps_hash:
# wrong hash, forget it
contact.caps_node = ''
contact.caps_hash_method = ''
contact.caps_hash = ''
return
# if we don't have this info already...
caps = gajim.capscache[(contact.caps_hash_method, contact.caps_hash)]
else:
# if we don't have this info already...
caps = gajim.capscache[(contact.caps_hash_method, contact.caps_node + \
'#' + contact.caps_hash)]
if caps.queried == 2:
return
caps.update(identities, features) lookup = contact.client_caps.get_cache_lookup_strategy()
cache_item = lookup(gajim.capscache)
if cache_item.queried == 2:
return
else:
validate = contact.client_caps.get_hash_validation_strategy()
hash_is_valid = validate(identities, features, dataforms)
if hash_is_valid:
cache_item.update(identities, features)
else:
contact.client_caps = NullClientCaps()
# vim: se ts=3: # vim: se ts=3:

View File

@ -1303,10 +1303,7 @@ class Connection(ConnectionHandlers):
# remove notexistant check # remove notexistant check
if ((composing_xep == 'XEP-0085' or not composing_xep) \ if ((composing_xep == 'XEP-0085' or not composing_xep) \
and composing_xep != 'asked_once') or \ and composing_xep != 'asked_once') or \
(gajim.capscache.is_supported(contact, contact.supports(common.xmpp.NS_CHATSTATES):
common.xmpp.NS_CHATSTATES) and \
not gajim.capscache.is_supported(contact,
'notexistant')):
# XEP-0085 # XEP-0085
msg_iq.setTag(chatstate, namespace=common.xmpp.NS_CHATSTATES) msg_iq.setTag(chatstate, namespace=common.xmpp.NS_CHATSTATES)
if composing_xep in ('XEP-0022', 'asked_once') or \ if composing_xep in ('XEP-0022', 'asked_once') or \
@ -1332,8 +1329,7 @@ class Connection(ConnectionHandlers):
# XEP-0184 # XEP-0184
if msgtxt and gajim.config.get_per('accounts', self.name, if msgtxt and gajim.config.get_per('accounts', self.name,
'request_receipt') and gajim.capscache.is_supported(contact, 'request_receipt') and contact.supports(common.xmpp.NS_RECEIPTS):
common.xmpp.NS_RECEIPTS):
msg_iq.setTag('request', namespace=common.xmpp.NS_RECEIPTS) msg_iq.setTag('request', namespace=common.xmpp.NS_RECEIPTS)
if session: if session:

View File

@ -2460,9 +2460,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
if not sess.received_thread_id: if not sess.received_thread_id:
contact = gajim.contacts.get_contact(self.name, jid) contact = gajim.contacts.get_contact(self.name, jid)
session_supported = gajim.capscache.is_supported(contact, session_supported = contact.supports(common.xmpp.NS_SSN) or \
common.xmpp.NS_SSN) or gajim.capscache.is_supported( contact.supports(common.xmpp.NS_ESESSION)
contact, common.xmpp.NS_ESESSION)
if session_supported: if session_supported:
sess.terminate() sess.terminate()
del self.sessions[jid][sess.thread_id] del self.sessions[jid][sess.thread_id]

View File

@ -53,7 +53,7 @@ class Contact(object):
self.keyID = keyID self.keyID = keyID
# Entity Capabilities # Entity Capabilities
self._client_caps = client_caps or NullClientCaps() self.client_caps = client_caps or NullClientCaps()
self._caps_cache = caps_cache or common.gajim.capscache self._caps_cache = caps_cache or common.gajim.capscache
# please read xep-85 http://www.xmpp.org/extensions/xep-0085.html # please read xep-85 http://www.xmpp.org/extensions/xep-0085.html
@ -147,8 +147,8 @@ class Contact(object):
return self._client_supports(requested_feature) return self._client_supports(requested_feature)
def _client_supports(self, requested_feature): def _client_supports(self, requested_feature):
lookup_item = self._client_caps.get_cache_lookup_strategy() lookup = self.client_caps.get_cache_lookup_strategy()
cache_item = lookup_item(self._caps_cache) cache_item = lookup(self._caps_cache)
supported_features = cache_item.features supported_features = cache_item.features
if requested_feature in supported_features: if requested_feature in supported_features:
@ -160,11 +160,6 @@ class Contact(object):
else: else:
return False return False
def set_supported_client_caps(self, client_caps):
''' Set an EntityCapabilities object '''
self._client_caps = client_caps
class GC_Contact: class GC_Contact:
'''Information concerning each groupchat contact''' '''Information concerning each groupchat contact'''
def __init__(self, room_jid='', name='', show='', status='', role='', def __init__(self, room_jid='', name='', show='', status='', role='',
@ -180,7 +175,7 @@ class GC_Contact:
self.resource = resource self.resource = resource
# Entity Capabilities # Entity Capabilities
self._client_caps = NullClientCaps() self.client_caps = NullClientCaps()
self._caps_cache = common.gajim.capscache self._caps_cache = common.gajim.capscache
self.our_chatstate = our_chatstate self.our_chatstate = our_chatstate
@ -204,7 +199,7 @@ class GC_Contact:
return self._client_supports(requested_feature) return self._client_supports(requested_feature)
def _client_supports(self, requested_feature): def _client_supports(self, requested_feature):
lookup_item = self._client_caps.get_cache_lookup_strategy() lookup_item = self.client_caps.get_cache_lookup_strategy()
cache_item = lookup_item(self._caps_cache) cache_item = lookup_item(self._caps_cache)
supported_features = cache_item.features supported_features = cache_item.features
@ -217,10 +212,6 @@ class GC_Contact:
else: else:
return False return False
def set_supported_client_caps(self, client_caps):
''' Set an EntityCapabilities object '''
self._client_caps = client_caps
class Contacts: class Contacts:
'''Information concerning all contacts and groupchat contacts''' '''Information concerning all contacts and groupchat contacts'''
def __init__(self): def __init__(self):
@ -276,7 +267,7 @@ class Contacts:
groups=contact.groups, show=contact.show, status=contact.status, groups=contact.groups, show=contact.show, status=contact.status,
sub=contact.sub, ask=contact.ask, resource=contact.resource, sub=contact.sub, ask=contact.ask, resource=contact.resource,
priority=contact.priority, keyID=contact.keyID, priority=contact.priority, keyID=contact.keyID,
client_caps=contact._client_caps, caps_cache=contact._caps_cache, client_caps=contact.client_caps, caps_cache=contact._caps_cache,
our_chatstate=contact.our_chatstate, our_chatstate=contact.our_chatstate,
chatstate=contact.chatstate, last_status_time=contact.last_status_time) chatstate=contact.chatstate, last_status_time=contact.last_status_time)
@ -647,7 +638,7 @@ class Contacts:
jid = gc_contact.get_full_jid() jid = gc_contact.get_full_jid()
return Contact(jid=jid, resource=gc_contact.resource, return Contact(jid=jid, resource=gc_contact.resource,
name=gc_contact.name, groups=[], show=gc_contact.show, name=gc_contact.name, groups=[], show=gc_contact.show,
status=gc_contact.status, sub='none', client_caps=gc_contact._client_caps, status=gc_contact.status, sub='none', client_caps=gc_contact.client_caps,
caps_cache=gc_contact._caps_cache) caps_cache=gc_contact._caps_cache)
def create_gc_contact(self, room_jid='', name='', show='', status='', def create_gc_contact(self, room_jid='', name='', show='', status='',

View File

@ -223,7 +223,7 @@ class EncryptedStanzaSession(StanzaSession):
def _is_buggy_gajim(self): def _is_buggy_gajim(self):
c = self._get_contact() c = self._get_contact()
if gajim.capscache.is_supported(c, xmpp.NS_ROSTERX): if c.supports(xmpp.NS_ROSTERX):
return False return False
return True return True

View File

@ -4060,7 +4060,7 @@ class RosterWindow:
return return
c_dest = gajim.contacts.get_contact_with_highest_priority(account_dest, c_dest = gajim.contacts.get_contact_with_highest_priority(account_dest,
jid_dest) jid_dest)
if not gajim.capscache.is_supported(c_dest, NS_FILE): if not c_dest.supports(NS_FILE):
return return
uri = data.strip() uri = data.strip()
uri_splitted = uri.split() # we may have more than one file dropped uri_splitted = uri.split() # we may have more than one file dropped
@ -5411,7 +5411,7 @@ class RosterWindow:
start_chat_menuitem.connect('activate', start_chat_menuitem.connect('activate',
self.on_roster_treeview_row_activated, tree_path) self.on_roster_treeview_row_activated, tree_path)
if gajim.capscache.is_supported(contact, NS_FILE): if contact.supports(NS_FILE):
send_file_menuitem.set_sensitive(True) send_file_menuitem.set_sensitive(True)
send_file_menuitem.connect('activate', send_file_menuitem.connect('activate',
self.on_send_file_menuitem_activate, contact, account) self.on_send_file_menuitem_activate, contact, account)
@ -5584,7 +5584,7 @@ class RosterWindow:
else: # one resource else: # one resource
start_chat_menuitem.connect('activate', start_chat_menuitem.connect('activate',
gajim.interface.on_open_chat_window, contact, account) gajim.interface.on_open_chat_window, contact, account)
if gajim.capscache.is_supported(contact, NS_COMMANDS): if contact.supports(NS_COMMANDS):
execute_command_menuitem.set_sensitive(True) execute_command_menuitem.set_sensitive(True)
execute_command_menuitem.connect('activate', self.on_execute_command, execute_command_menuitem.connect('activate', self.on_execute_command,
contact, account, contact.resource) contact, account, contact.resource)
@ -5598,7 +5598,7 @@ class RosterWindow:
# our_jid_other_resource = contact.resource # our_jid_other_resource = contact.resource
# Else this var is useless but harmless in next connect calls # Else this var is useless but harmless in next connect calls
if gajim.capscache.is_supported(contact, NS_FILE): if contact.supports(NS_FILE):
send_file_menuitem.set_sensitive(True) send_file_menuitem.set_sensitive(True)
send_file_menuitem.connect('activate', send_file_menuitem.connect('activate',
self.on_send_file_menuitem_activate, contact, account) self.on_send_file_menuitem_activate, contact, account)
@ -6026,8 +6026,7 @@ class RosterWindow:
item.connect('activate', action, [(c, account)], c.resource) item.connect('activate', action, [(c, account)], c.resource)
else: # start_chat, execute_command, send_file else: # start_chat, execute_command, send_file
item.connect('activate', action, c, account, c.resource) item.connect('activate', action, c, account, c.resource)
if cap and \ if cap and not c.suppors(cap):
not gajim.capscache.is_supported(c, cap):
item.set_sensitive(False) item.set_sensitive(False)
return sub_menu return sub_menu
@ -6062,7 +6061,7 @@ class RosterWindow:
if len(contact_list) > 1: # several resources if len(contact_list) > 1: # several resources
invite_to_new_room_menuitem.set_submenu(self.build_resources_submenu( invite_to_new_room_menuitem.set_submenu(self.build_resources_submenu(
contact_list, account, self.on_invite_to_new_room, cap=NS_MUC)) contact_list, account, self.on_invite_to_new_room, cap=NS_MUC))
elif len(list_) == 1 and gajim.capscache.is_supported(contact, NS_MUC): elif len(list_) == 1 and contact.supports(NS_MUC):
invite_menuitem.set_sensitive(True) invite_menuitem.set_sensitive(True)
# use resource if it's self contact # use resource if it's self contact
if contact.jid == gajim.get_jid_from_account(account): if contact.jid == gajim.get_jid_from_account(account):

View File

@ -118,8 +118,7 @@ class TestClientCaps(CommonCapsTest):
"http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=") "http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=")
def test_client_supports(self): def test_client_supports(self):
contact = Contact(caps_cache=self.cc) contact = Contact(caps_cache=self.cc, client_caps=self.client_caps)
contact.set_supported_client_caps(self.client_caps)
self.assertTrue(contact.supports(NS_PING), self.assertTrue(contact.supports(NS_PING),
msg="Assume supported, if we don't have caps") msg="Assume supported, if we don't have caps")

View File

@ -24,8 +24,7 @@ class TestCommonContact(unittest.TestCase):
self.assertTrue(self.contact.supports(NS_MUC), self.assertTrue(self.contact.supports(NS_MUC),
msg="Must not backtrace on simple check for supported feature") msg="Must not backtrace on simple check for supported feature")
client_caps = NullClientCaps() self.contact.client_caps = NullClientCaps()
self.contact.set_supported_client_caps(client_caps)
self.assertTrue(self.contact.supports(NS_MUC), self.assertTrue(self.contact.supports(NS_MUC),
msg="Must not backtrace on simple check for supported feature") msg="Must not backtrace on simple check for supported feature")