From 33fe53ff7d9a8a67fa2e0d1577dac78c33f8d0c1 Mon Sep 17 00:00:00 2001 From: Stephan Erb Date: Tue, 27 Oct 2009 22:41:39 +0100 Subject: [PATCH] Swtich from old to new caps API. Now we do: contact.supports(feauture) instead of gajim.capscache.is_supported(contact, feature) --- src/chat_control.py | 30 +++------ src/common/caps.py | 106 ++++++++++++++++-------------- src/common/connection.py | 8 +-- src/common/connection_handlers.py | 5 +- src/common/contacts.py | 23 ++----- src/common/stanza_session.py | 2 +- src/roster_window.py | 13 ++-- test/test_caps.py | 3 +- test/test_contacts.py | 3 +- 9 files changed, 84 insertions(+), 109 deletions(-) diff --git a/src/chat_control.py b/src/chat_control.py index 75ee9ef4a..a775e248f 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -1333,9 +1333,7 @@ class ChatControl(ChatControlBase): def update_toolbar(self): # Formatting - if gajim.capscache.is_supported(self.contact, NS_XHTML_IM) \ - and not gajim.capscache.is_supported(self.contact, 'notexistant') \ - and not self.gpg_is_active: + if self.contact.supports(NS_XHTML_IM) and not self.gpg_is_active: self._formattings_button.set_sensitive(True) else: self._formattings_button.set_sensitive(False) @@ -1348,12 +1346,11 @@ class ChatControl(ChatControlBase): self._add_to_roster_button.hide() # Send file - if gajim.capscache.is_supported(self.contact, NS_FILE) and \ - self.contact.resource: + if self.contact.supports(NS_FILE) and self.contact.resource: self._send_file_button.set_sensitive(True) else: 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(_( "This contact does not support file transfer.")) else: @@ -1362,7 +1359,7 @@ class ChatControl(ChatControlBase): "her a file.")) # 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) else: self._convert_to_gc_button.set_sensitive(False) @@ -1828,9 +1825,7 @@ class ChatControl(ChatControlBase): def _on_sent(id_, contact, message, encrypted, xhtml): # XXX: Once we have fallback to disco, remove notexistant check - if gajim.capscache.is_supported(contact, NS_RECEIPTS) \ - and not gajim.capscache.is_supported(contact, - 'notexistant') and gajim.config.get_per('accounts', + if contact.supports(NS_RECEIPTS) and gajim.config.get_per('accounts', self.account, 'request_receipt'): xep0184_id = id_ else: @@ -2137,10 +2132,7 @@ class ChatControl(ChatControlBase): toggle_gpg_menuitem.set_active(self.gpg_is_active) # 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 gajim.capscache.is_supported(contact, NS_ESESSION) or \ - gajim.capscache.is_supported(contact, 'notexistant') or \ + if not gajim.HAVE_PYCRYPTO or not contact.supports(NS_ESESSION) or \ not gajim.config.get_per('accounts', self.account, 'enable_esessions'): toggle_e2e_menuitem.set_sensitive(False) else: @@ -2152,13 +2144,13 @@ class ChatControl(ChatControlBase): add_to_roster_menuitem.show() # 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) else: send_file_menuitem.set_sensitive(False) # 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) else: 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 \ and e2e_pref - # XXX: Once we have fallback to disco, remove notexistant check if want_e2e and not self.no_autonegotiation \ - and gajim.HAVE_PYCRYPTO \ - and gajim.capscache.is_supported(self.contact, - NS_ESESSION) and not gajim.capscache.is_supported( - self.contact, 'notexistant'): + and gajim.HAVE_PYCRYPTO and self.contact.supports(NS_ESESSION): self.begin_e2e_negotiation() else: self.send_chatstate('active', self.contact) diff --git a/src/common/caps.py b/src/common/caps.py index fbda610b1..9ff0c8e75 100644 --- a/src/common/caps.py +++ b/src/common/caps.py @@ -65,8 +65,14 @@ class AbstractClientCaps(object): def _lookup_in_cache(self, caps_cache): ''' To be implemented by subclassess ''' 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): ''' The current XEP-115 implementation ''' @@ -81,6 +87,11 @@ class ClientCaps(AbstractClientCaps): def _discover(self, connection, jid): 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): ''' Old XEP-115 implemtation. Kept around for background competability. ''' @@ -94,6 +105,8 @@ class OldClientCaps(AbstractClientCaps): def _discover(self, connection, jid): connection.discoverInfo(jid) + def _is_hash_valid(self, identities, features, dataforms): + return True class NullClientCaps(AbstractClientCaps): ''' @@ -112,6 +125,8 @@ class NullClientCaps(AbstractClientCaps): def _discover(self, connection, jid): pass + def _is_hash_valid(self, identities, features, dataforms): + return False class CapsCache(object): ''' @@ -238,11 +253,17 @@ class CapsCache(object): gajim.capscache = CapsCache(gajim.logger) + 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): - ''' 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 # for disco... so that disco will learn how to interpret @@ -264,64 +285,47 @@ class ConnectionCaps(object): # into Contacts return - # get the caps element - caps = presence.getTag('c') - if not caps: - contact.caps_node = None - contact.caps_hash = None - contact.caps_hash_method = None - return + caps_tag = presence.getTag('c') + if not caps_tag: + # presence did not contain caps_tag + client_caps = NullClientCaps() + else: + hash_method, node, caps_hash = caps_tag['hash'], caps_tag['node'], caps_tag['ver'] - 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: 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) if not contact: room_jid, nick = gajim.get_room_and_nick_from_fjid(jid) contact = gajim.contacts.get_gc_contact(self.name, room_jid, nick) if contact is None: 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: diff --git a/src/common/connection.py b/src/common/connection.py index 36595d8d8..5ec741051 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -1303,10 +1303,7 @@ class Connection(ConnectionHandlers): # remove notexistant check if ((composing_xep == 'XEP-0085' or not composing_xep) \ and composing_xep != 'asked_once') or \ - (gajim.capscache.is_supported(contact, - common.xmpp.NS_CHATSTATES) and \ - not gajim.capscache.is_supported(contact, - 'notexistant')): + contact.supports(common.xmpp.NS_CHATSTATES): # XEP-0085 msg_iq.setTag(chatstate, namespace=common.xmpp.NS_CHATSTATES) if composing_xep in ('XEP-0022', 'asked_once') or \ @@ -1332,8 +1329,7 @@ class Connection(ConnectionHandlers): # XEP-0184 if msgtxt and gajim.config.get_per('accounts', self.name, - 'request_receipt') and gajim.capscache.is_supported(contact, - common.xmpp.NS_RECEIPTS): + 'request_receipt') and contact.supports(common.xmpp.NS_RECEIPTS): msg_iq.setTag('request', namespace=common.xmpp.NS_RECEIPTS) if session: diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py index f90281246..b40f4500d 100644 --- a/src/common/connection_handlers.py +++ b/src/common/connection_handlers.py @@ -2460,9 +2460,8 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, if not sess.received_thread_id: contact = gajim.contacts.get_contact(self.name, jid) - session_supported = gajim.capscache.is_supported(contact, - common.xmpp.NS_SSN) or gajim.capscache.is_supported( - contact, common.xmpp.NS_ESESSION) + session_supported = contact.supports(common.xmpp.NS_SSN) or \ + contact.supports(common.xmpp.NS_ESESSION) if session_supported: sess.terminate() del self.sessions[jid][sess.thread_id] diff --git a/src/common/contacts.py b/src/common/contacts.py index 05d7cfe1b..b4234d15d 100644 --- a/src/common/contacts.py +++ b/src/common/contacts.py @@ -53,7 +53,7 @@ class Contact(object): self.keyID = keyID # 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 # 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) def _client_supports(self, requested_feature): - lookup_item = self._client_caps.get_cache_lookup_strategy() - cache_item = lookup_item(self._caps_cache) + lookup = self.client_caps.get_cache_lookup_strategy() + cache_item = lookup(self._caps_cache) supported_features = cache_item.features if requested_feature in supported_features: @@ -160,11 +160,6 @@ class Contact(object): else: return False - def set_supported_client_caps(self, client_caps): - ''' Set an EntityCapabilities object ''' - self._client_caps = client_caps - - class GC_Contact: '''Information concerning each groupchat contact''' def __init__(self, room_jid='', name='', show='', status='', role='', @@ -180,7 +175,7 @@ class GC_Contact: self.resource = resource # Entity Capabilities - self._client_caps = NullClientCaps() + self.client_caps = NullClientCaps() self._caps_cache = common.gajim.capscache self.our_chatstate = our_chatstate @@ -204,7 +199,7 @@ class GC_Contact: return self._client_supports(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) supported_features = cache_item.features @@ -217,10 +212,6 @@ class GC_Contact: else: return False - def set_supported_client_caps(self, client_caps): - ''' Set an EntityCapabilities object ''' - self._client_caps = client_caps - class Contacts: '''Information concerning all contacts and groupchat contacts''' def __init__(self): @@ -276,7 +267,7 @@ class Contacts: groups=contact.groups, show=contact.show, status=contact.status, sub=contact.sub, ask=contact.ask, resource=contact.resource, 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, chatstate=contact.chatstate, last_status_time=contact.last_status_time) @@ -647,7 +638,7 @@ class Contacts: jid = gc_contact.get_full_jid() return Contact(jid=jid, resource=gc_contact.resource, 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) def create_gc_contact(self, room_jid='', name='', show='', status='', diff --git a/src/common/stanza_session.py b/src/common/stanza_session.py index cedf01553..6e6043077 100644 --- a/src/common/stanza_session.py +++ b/src/common/stanza_session.py @@ -223,7 +223,7 @@ class EncryptedStanzaSession(StanzaSession): def _is_buggy_gajim(self): c = self._get_contact() - if gajim.capscache.is_supported(c, xmpp.NS_ROSTERX): + if c.supports(xmpp.NS_ROSTERX): return False return True diff --git a/src/roster_window.py b/src/roster_window.py index f5981d384..378773955 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -4060,7 +4060,7 @@ class RosterWindow: return c_dest = gajim.contacts.get_contact_with_highest_priority(account_dest, jid_dest) - if not gajim.capscache.is_supported(c_dest, NS_FILE): + if not c_dest.supports(NS_FILE): return uri = data.strip() uri_splitted = uri.split() # we may have more than one file dropped @@ -5411,7 +5411,7 @@ class RosterWindow: start_chat_menuitem.connect('activate', 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.connect('activate', self.on_send_file_menuitem_activate, contact, account) @@ -5584,7 +5584,7 @@ class RosterWindow: else: # one resource start_chat_menuitem.connect('activate', 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.connect('activate', self.on_execute_command, contact, account, contact.resource) @@ -5598,7 +5598,7 @@ class RosterWindow: # our_jid_other_resource = contact.resource # 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.connect('activate', self.on_send_file_menuitem_activate, contact, account) @@ -6026,8 +6026,7 @@ class RosterWindow: item.connect('activate', action, [(c, account)], c.resource) else: # start_chat, execute_command, send_file item.connect('activate', action, c, account, c.resource) - if cap and \ - not gajim.capscache.is_supported(c, cap): + if cap and not c.suppors(cap): item.set_sensitive(False) return sub_menu @@ -6062,7 +6061,7 @@ class RosterWindow: if len(contact_list) > 1: # several resources invite_to_new_room_menuitem.set_submenu(self.build_resources_submenu( 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) # use resource if it's self contact if contact.jid == gajim.get_jid_from_account(account): diff --git a/test/test_caps.py b/test/test_caps.py index 5e0918ea6..35c4678de 100644 --- a/test/test_caps.py +++ b/test/test_caps.py @@ -118,8 +118,7 @@ class TestClientCaps(CommonCapsTest): "http://gajim.org#m3P2WeXPMGVH2tZPe7yITnfY0Dw=") def test_client_supports(self): - contact = Contact(caps_cache=self.cc) - contact.set_supported_client_caps(self.client_caps) + contact = Contact(caps_cache=self.cc, client_caps=self.client_caps) self.assertTrue(contact.supports(NS_PING), msg="Assume supported, if we don't have caps") diff --git a/test/test_contacts.py b/test/test_contacts.py index 1ddce82e9..1fe3dc033 100644 --- a/test/test_contacts.py +++ b/test/test_contacts.py @@ -24,8 +24,7 @@ class TestCommonContact(unittest.TestCase): self.assertTrue(self.contact.supports(NS_MUC), msg="Must not backtrace on simple check for supported feature") - client_caps = NullClientCaps() - self.contact.set_supported_client_caps(client_caps) + self.contact.client_caps = NullClientCaps() self.assertTrue(self.contact.supports(NS_MUC), msg="Must not backtrace on simple check for supported feature")