Move compute_caps_hash from helpers to caps module.

This commit is contained in:
Stephan Erb 2009-10-30 23:55:03 +01:00
parent 47f875a4bc
commit 99e8487db9
4 changed files with 78 additions and 75 deletions

View File

@ -33,6 +33,8 @@ through ClientCaps objects which are hold by contact instances.
import gajim import gajim
import helpers import helpers
import base64
import hashlib
from common.xmpp import NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION, NS_CHATSTATES from common.xmpp import NS_XHTML_IM, NS_RECEIPTS, NS_ESESSION, NS_CHATSTATES
# Features where we cannot safely assume that the other side supports them # Features where we cannot safely assume that the other side supports them
@ -46,6 +48,76 @@ def initialize(logger):
capscache = CapsCache(logger) capscache = CapsCache(logger)
def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'):
'''Compute caps hash according to XEP-0115, V1.5
dataforms are xmpp.DataForms objects as common.dataforms don't allow several
values without a field type list-multi'''
def sort_identities_func(i1, i2):
cat1 = i1['category']
cat2 = i2['category']
if cat1 < cat2:
return -1
if cat1 > cat2:
return 1
type1 = i1.get('type', '')
type2 = i2.get('type', '')
if type1 < type2:
return -1
if type1 > type2:
return 1
lang1 = i1.get('xml:lang', '')
lang2 = i2.get('xml:lang', '')
if lang1 < lang2:
return -1
if lang1 > lang2:
return 1
return 0
def sort_dataforms_func(d1, d2):
f1 = d1.getField('FORM_TYPE')
f2 = d2.getField('FORM_TYPE')
if f1 and f2 and (f1.getValue() < f2.getValue()):
return -1
return 1
S = ''
identities.sort(cmp=sort_identities_func)
for i in identities:
c = i['category']
type_ = i.get('type', '')
lang = i.get('xml:lang', '')
name = i.get('name', '')
S += '%s/%s/%s/%s<' % (c, type_, lang, name)
features.sort()
for f in features:
S += '%s<' % f
dataforms.sort(cmp=sort_dataforms_func)
for dataform in dataforms:
# fields indexed by var
fields = {}
for f in dataform.getChildren():
fields[f.getVar()] = f
form_type = fields.get('FORM_TYPE')
if form_type:
S += form_type.getValue() + '<'
del fields['FORM_TYPE']
for var in sorted(fields.keys()):
S += '%s<' % var
values = sorted(fields[var].getValues())
for value in values:
S += '%s<' % value
if hash_method == 'sha-1':
hash_ = hashlib.sha1(S)
elif hash_method == 'md5':
hash_ = hashlib.md5(S)
else:
return ''
return base64.b64encode(hash_.digest())
class AbstractClientCaps(object): class AbstractClientCaps(object):
''' '''
Base class representing a client and its capabilities as advertised by Base class representing a client and its capabilities as advertised by
@ -92,7 +164,7 @@ class ClientCaps(AbstractClientCaps):
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): def _is_hash_valid(self, identities, features, dataforms):
computed_hash = helpers.compute_caps_hash(identities, features, computed_hash = compute_caps_hash(identities, features,
dataforms=dataforms, hash_method=self._hash_method) dataforms=dataforms, hash_method=self._hash_method)
return computed_hash == self._hash return computed_hash == self._hash

View File

@ -37,8 +37,8 @@ import urllib
import errno import errno
import select import select
import base64 import base64
import sys
import hashlib import hashlib
import caps
from encodings.punycode import punycode_encode from encodings.punycode import punycode_encode
@ -566,74 +566,6 @@ def datetime_tuple(timestamp):
from time import strptime from time import strptime
return strptime(timestamp, '%Y%m%dT%H:%M:%S') return strptime(timestamp, '%Y%m%dT%H:%M:%S')
def sort_identities_func(i1, i2):
cat1 = i1['category']
cat2 = i2['category']
if cat1 < cat2:
return -1
if cat1 > cat2:
return 1
type1 = i1.get('type', '')
type2 = i2.get('type', '')
if type1 < type2:
return -1
if type1 > type2:
return 1
lang1 = i1.get('xml:lang', '')
lang2 = i2.get('xml:lang', '')
if lang1 < lang2:
return -1
if lang1 > lang2:
return 1
return 0
def sort_dataforms_func(d1, d2):
f1 = d1.getField('FORM_TYPE')
f2 = d2.getField('FORM_TYPE')
if f1 and f2 and (f1.getValue() < f2.getValue()):
return -1
return 1
def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'):
'''Compute caps hash according to XEP-0115, V1.5
dataforms are xmpp.DataForms objects as common.dataforms don't allow several
values without a field type list-multi'''
S = ''
identities.sort(cmp=sort_identities_func)
for i in identities:
c = i['category']
type_ = i.get('type', '')
lang = i.get('xml:lang', '')
name = i.get('name', '')
S += '%s/%s/%s/%s<' % (c, type_, lang, name)
features.sort()
for f in features:
S += '%s<' % f
dataforms.sort(cmp=sort_dataforms_func)
for dataform in dataforms:
# fields indexed by var
fields = {}
for f in dataform.getChildren():
fields[f.getVar()] = f
form_type = fields.get('FORM_TYPE')
if form_type:
S += form_type.getValue() + '<'
del fields['FORM_TYPE']
for var in sorted(fields.keys()):
S += '%s<' % var
values = sorted(fields[var].getValues())
for value in values:
S += '%s<' % value
if hash_method == 'sha-1':
hash_ = hashlib.sha1(S)
elif hash_method == 'md5':
hash_ = hashlib.md5(S)
else:
return ''
return base64.b64encode(hash_.digest())
# import gajim only when needed (after decode_string is defined) see #4764 # import gajim only when needed (after decode_string is defined) see #4764
import gajim import gajim
@ -1357,7 +1289,7 @@ def update_optional_features(account = None):
gajim.gajim_optional_features[a].append(xmpp.NS_ESESSION) gajim.gajim_optional_features[a].append(xmpp.NS_ESESSION)
if gajim.config.get_per('accounts', a, 'answer_receipts'): if gajim.config.get_per('accounts', a, 'answer_receipts'):
gajim.gajim_optional_features[a].append(xmpp.NS_RECEIPTS) gajim.gajim_optional_features[a].append(xmpp.NS_RECEIPTS)
gajim.caps_hash[a] = compute_caps_hash([gajim.gajim_identity], gajim.caps_hash[a] = caps.compute_caps_hash([gajim.gajim_identity],
gajim.gajim_common_features + gajim.gajim_optional_features[a]) gajim.gajim_common_features + gajim.gajim_optional_features[a])
# re-send presence with new hash # re-send presence with new hash
connected = gajim.connections[a].connected connected = gajim.connections[a].connected

View File

@ -31,6 +31,7 @@ import locale
import re import re
from common import gajim from common import gajim
from common import helpers from common import helpers
from common import caps
import exceptions import exceptions
try: try:
@ -216,7 +217,7 @@ class OptionsParser:
gajim.logger.init_vars() gajim.logger.init_vars()
gajim.config.set('version', new_version) gajim.config.set('version', new_version)
gajim.capscache.initialize_from_db() caps.capscache.initialize_from_db()
def update_config_x_to_09(self): def update_config_x_to_09(self):
# Var name that changed: # Var name that changed:

View File

@ -6,8 +6,6 @@ import unittest
import lib import lib
lib.setup_env() lib.setup_env()
from common import gajim
from common import helpers
from common.xmpp import NS_MUC, NS_PING, NS_XHTML_IM from common.xmpp import NS_MUC, NS_PING, NS_XHTML_IM
from common import caps from common import caps
from common.contacts import Contact from common.contacts import Contact
@ -95,7 +93,7 @@ class TestCapsCache(CommonCapsTest):
def test_hash(self): def test_hash(self):
'''tests the hash computation''' '''tests the hash computation'''
computed_hash = helpers.compute_caps_hash(self.identities, self.features) computed_hash = caps.compute_caps_hash(self.identities, self.features)
self.assertEqual(self.caps_hash, computed_hash) self.assertEqual(self.caps_hash, computed_hash)