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 helpers
import base64
import hashlib
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
@ -44,6 +46,76 @@ def initialize(logger):
''' Initializes the capscache global '''
global capscache
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):
@ -92,7 +164,7 @@ class ClientCaps(AbstractClientCaps):
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,
computed_hash = compute_caps_hash(identities, features,
dataforms=dataforms, hash_method=self._hash_method)
return computed_hash == self._hash

View File

@ -37,8 +37,8 @@ import urllib
import errno
import select
import base64
import sys
import hashlib
import caps
from encodings.punycode import punycode_encode
@ -566,74 +566,6 @@ def datetime_tuple(timestamp):
from time import strptime
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
@ -1357,7 +1289,7 @@ def update_optional_features(account = None):
gajim.gajim_optional_features[a].append(xmpp.NS_ESESSION)
if gajim.config.get_per('accounts', a, 'answer_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])
# re-send presence with new hash
connected = gajim.connections[a].connected

View File

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

View File

@ -6,8 +6,6 @@ import unittest
import lib
lib.setup_env()
from common import gajim
from common import helpers
from common.xmpp import NS_MUC, NS_PING, NS_XHTML_IM
from common import caps
from common.contacts import Contact
@ -95,7 +93,7 @@ class TestCapsCache(CommonCapsTest):
def test_hash(self):
'''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)