Move compute_caps_hash from helpers to caps module.
This commit is contained in:
parent
47f875a4bc
commit
99e8487db9
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue