new XEP-0115 implementation (version 1.5)

This commit is contained in:
Yann Leboulanger 2008-04-20 22:58:47 +00:00
parent be310652c4
commit a3827fe5d0
13 changed files with 274 additions and 195 deletions

View File

@ -1,5 +1,5 @@
AC_INIT([Gajim - A Jabber Instant Messager],
[0.11.4.3-svn],[http://trac.gajim.org/],[gajim])
[0.11.4.4-svn],[http://trac.gajim.org/],[gajim])
AC_PREREQ([2.59])
AM_INIT_AUTOMAKE([1.8])
AC_CONFIG_HEADER(config.h)

View File

@ -20,6 +20,7 @@ from itertools import *
import xmpp
import xmpp.features_nb
import gajim
import helpers
class CapsCache(object):
''' This object keeps the mapping between caps data and real disco
@ -93,17 +94,30 @@ class CapsCache(object):
class CacheItem(object):
''' TODO: logging data into db '''
def __init__(ciself, node, version, ext=None):
def __init__(ciself, hash_method, hash):
# cached into db
ciself.node = node
ciself.version = version
ciself.features = set()
ciself.ext = ext
ciself.exts = {}
ciself.hash_method = hash_method
ciself.hash = hash
# set of tuples: (category, type, name)
# (dictionaries are not hashable, so cannot be in sets)
ciself.identities = set()
@property
def features():
def fget(self):
return self.getAttr('features')
def fset(self, value):
list_ = []
for feature in value:
list_.append(self.__names.setdefault(feature, feature))
self.setAttr('features', list_)
@property
def identities():
def fget(self):
return self.getAttr('identities')
def fset(self, value):
list_ = []
for identity in value:
list_.append(self.__names.setdefault(identity, identity))
self.setAttr('identities', list_)
# not cached into db:
# have we sent the query?
@ -112,53 +126,21 @@ class CapsCache(object):
# 2 == got the answer
ciself.queried = 0
class CacheQuery(object):
def __init__(cqself, proxied):
cqself.proxied=proxied
def __getattr__(cqself, obj):
if obj!='exts': return getattr(cqself.proxied[0], obj)
return set(chain(ci.features for ci in cqself.proxied))
def __getitem__(ciself, exts):
if not exts: # (), [], None, False, whatever
return ciself
if isinstance(exts, basestring):
exts=(exts,)
if len(exts)==1:
ext=exts[0]
if ext in ciself.exts:
return ciself.exts[ext]
x=CacheItem(ciself.node, ciself.version, ext)
ciself.exts[ext]=x
return x
proxied = [ciself]
proxied.extend(ciself[(e,)] for e in exts)
return ciself.CacheQuery(proxied)
def update(ciself, identities, features):
# NOTE: self refers to CapsCache object, not to CacheItem
self.identities=identities
self.features=features
self.logger.add_caps_entry(
ciself.node, ciself.version, ciself.ext,
ciself.identities=identities
ciself.features=features
self.logger.add_caps_entry(ciself.hash_method, ciself.hash,
identities, features)
self.__CacheItem = CacheItem
# prepopulate data which we are sure of; note: we do not log these info
gajimnode = 'http://gajim.org/caps'
gajimcaps=self[(gajimnode, '0.11.1')]
gajimcaps.category='client'
gajimcaps.type='pc'
gajimcaps.features=set((xmpp.NS_BYTESTREAM, xmpp.NS_SI,
xmpp.NS_FILE, xmpp.NS_MUC, xmpp.NS_COMMANDS,
xmpp.NS_DISCO_INFO, xmpp.NS_PING, xmpp.NS_TIME_REVISED))
gajimcaps['cstates'].features=set((xmpp.NS_CHATSTATES,))
gajimcaps['xhtml'].features=set((xmpp.NS_XHTML_IM,))
# TODO: older gajim versions
gajimcaps = self[('sha-1', gajim.caps_hash)]
gajimcaps.identities = [gajim.gajim_identity]
gajimcaps.features = gajim.gajim_common_features + \
gajim.gajim_optional_features
# start logging data from the net
self.logger = logger
@ -166,40 +148,32 @@ class CapsCache(object):
def load_from_db(self):
# get data from logger...
if self.logger is not None:
for node, ver, ext, identities, features in self.logger.iter_caps_data():
x=self[(node, ver, ext)]
x.identities=identities
x.features=features
x.queried=2
for hash_method, hash, identities, features in \
self.logger.iter_caps_data():
x = self[(hash_method, hash)]
x.identities = identities
x.features = features
x.queried = 2
def __getitem__(self, caps):
node_version = caps[:2]
if node_version in self.__cache:
return self.__cache[node_version][caps[2]]
node, version = self.__names.setdefault(caps[0], caps[0]), caps[1]
x=self.__CacheItem(node, version)
self.__cache[(node, version)]=x
if caps in self.__cache:
return self.__cache[caps]
hash_method, hash = caps[0], caps[1]
x = self.__CacheItem(hash_method, hash)
self.__cache[(hash_method, hash)] = x
return x
def preload(self, account, jid, node, ver, exts):
def preload(self, con, jid, node, hash_method, hash):
''' Preload data about (node, ver, exts) caps using disco
query to jid using proper connection. Don't query if
the data is already in cache. '''
q=self[(node, ver, ())]
qq=q
q = self[(hash_method, hash)]
if q.queried==0:
# do query for bare node+version pair
# do query for bare node+hash pair
# this will create proper object
q.queried=1
account.discoverInfo(jid, '%s#%s' % (node, ver))
for ext in exts:
qq=q[ext]
if qq.queried==0:
# do query for node+version+ext triple
qq.queried=1
account.discoverInfo(jid, '%s#%s' % (node, ext))
con.discoverInfo(jid, '%s#%s' % (node, hash))
gajim.capscache = CapsCache(gajim.logger)
@ -210,19 +184,14 @@ class ConnectionCaps(object):
for xmpp registered in connection_handlers.py'''
# get the caps element
caps=presence.getTag('c')
if not caps: return
node, ver=caps['node'], caps['ver']
if node is None or ver is None:
# improper caps in stanza, ignoring
caps = presence.getTag('c')
if not caps:
return
try:
exts=caps['ext'].split(' ')
except AttributeError:
# no exts means no exts, a perfectly valid case
exts=[]
hash_method, node, hash = caps['hash'], caps['node'], caps['ver']
if hash_method is None or node is None or hash is None:
# improper caps in stanza, ignoring
return
# we will put these into proper Contact object and ask
# for disco... so that disco will learn how to interpret
@ -231,7 +200,7 @@ class ConnectionCaps(object):
jid=str(presence.getFrom())
# start disco query...
gajim.capscache.preload(self, jid, node, ver, exts)
gajim.capscache.preload(self, jid, node, hash_method, hash)
contact=gajim.contacts.get_contact_from_full_jid(self.name, jid)
if contact in [None, []]:
@ -240,25 +209,31 @@ class ConnectionCaps(object):
contact = contact[0]
# overwriting old data
contact.caps_node=node
contact.caps_ver=ver
contact.caps_exts=exts
contact.caps_node = node
contact.caps_hash_method = hash_method
contact.caps_hash = hash
def _capsDiscoCB(self, jid, node, identities, features, data):
contact=gajim.contacts.get_contact_from_full_jid(self.name, jid)
if not contact: return
if not contact.caps_node: return # we didn't asked for that?
if not node.startswith(contact.caps_node+'#'): return
node, ext = node.split('#', 1)
if ext==contact.caps_ver: # this can be also version (like '0.9')
exts=None
else:
exts=(ext,)
contact = gajim.contacts.get_contact_from_full_jid(self.name, jid)
if not contact:
return
if not contact.caps_node:
return # we didn't asked for that?
if not node.startswith(contact.caps_node + '#'):
return
node, hash = node.split('#', 1)
computed_hash = helpers.compute_caps_hash(identities, features,
contact.caps_hash_method)
if computed_hash != 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[(node, contact.caps_ver, exts)]
if caps.queried==2: return
caps = gajim.capscache[(contact.caps_hash_method, hash)]
if caps.queried == 2:
return
identities=set((i['category'], i['type'], i.get('name')) for i in identities)
caps.update(identities, features)

View File

@ -82,9 +82,8 @@ def create_log_db():
CREATE INDEX idx_logs_jid_id_kind ON logs (jid_id, kind);
CREATE TABLE caps_cache (
node TEXT,
ver TEXT,
ext TEXT,
hash_method TEXT,
hash TEXT,
data BLOB);
CREATE TABLE IF NOT EXISTS rooms_last_message_time(

View File

@ -667,7 +667,7 @@ class ConnectionDisco:
common.xmpp.NS_DISCO, frm = to)
iq.setAttr('id', id)
query = iq.setTag('query')
query.setAttr('node','http://gajim.org/caps#' + gajim.version.split('-',
query.setAttr('node','http://gajim.org#' + gajim.version.split('-',
1)[0])
for f in (common.xmpp.NS_BYTESTREAM, common.xmpp.NS_SI,
common.xmpp.NS_FILE, common.xmpp.NS_COMMANDS):
@ -744,55 +744,17 @@ class ConnectionDisco:
q = iq.getTag('query')
if node:
q.setAttr('node', node)
q.addChild('identity', attrs = {'type': 'pc', 'category': 'client',
'name': 'Gajim'})
q.addChild('identity', attrs = gajim.gajim_identity)
extension = None
if node and node.find('#') != -1:
extension = node[node.index('#') + 1:]
client_version = 'http://gajim.org/caps#' + gajim.version.split('-',
1)[0]
client_version = 'http://gajim.org#' + gajim.caps_hash
if node in (None, client_version):
q.addChild('feature', attrs = {'var': common.xmpp.NS_BYTESTREAM})
q.addChild('feature', attrs = {'var': common.xmpp.NS_SI})
q.addChild('feature', attrs = {'var': common.xmpp.NS_FILE})
q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC})
q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC_USER})
q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC_ADMIN})
q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC_OWNER})
q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC_CONFIG})
q.addChild('feature', attrs = {'var': common.xmpp.NS_COMMANDS})
q.addChild('feature', attrs = {'var': common.xmpp.NS_DISCO_INFO})
q.addChild('feature', attrs = {'var': 'ipv6'})
q.addChild('feature', attrs = {'var': 'jabber:iq:gateway'})
q.addChild('feature', attrs = {'var': common.xmpp.NS_LAST})
q.addChild('feature', attrs = {'var': common.xmpp.NS_PRIVACY})
q.addChild('feature', attrs = {'var': common.xmpp.NS_PRIVATE})
q.addChild('feature', attrs = {'var': common.xmpp.NS_REGISTER})
q.addChild('feature', attrs = {'var': common.xmpp.NS_VERSION})
q.addChild('feature', attrs = {'var': common.xmpp.NS_DATA})
q.addChild('feature', attrs = {'var': common.xmpp.NS_ENCRYPTED})
q.addChild('feature', attrs = {'var': 'msglog'})
q.addChild('feature', attrs = {'var': 'sslc2s'})
q.addChild('feature', attrs = {'var': 'stringprep'})
q.addChild('feature', attrs = {'var': common.xmpp.NS_PING})
q.addChild('feature', attrs = {'var': common.xmpp.NS_ACTIVITY})
q.addChild('feature', attrs = {'var': common.xmpp.NS_ACTIVITY + '+notify'})
q.addChild('feature', attrs = {'var': common.xmpp.NS_TUNE})
q.addChild('feature', attrs = {'var': common.xmpp.NS_TUNE + '+notify'})
q.addChild('feature', attrs = {'var': common.xmpp.NS_MOOD})
q.addChild('feature', attrs = {'var': common.xmpp.NS_MOOD + '+notify'})
q.addChild('feature', attrs = {'var': common.xmpp.NS_ESESSION_INIT})
if (node is None or extension == 'cstates') and gajim.config.get('outgoing_chat_state_notifactions') != 'disabled':
q.addChild('feature', attrs = {'var': common.xmpp.NS_CHATSTATES})
if (node is None or extension == 'xhtml') and not gajim.config.get('ignore_incoming_xhtml'):
q.addChild('feature', attrs = {'var': common.xmpp.NS_XHTML_IM})
if node is None:
q.addChild('feature', attrs = {'var': common.xmpp.NS_PING})
q.addChild('feature', attrs = {'var': common.xmpp.NS_TIME_REVISED})
for f in gajim.gajim_common_features:
q.addChild('feature', attrs = {'var': f})
for f in gajim.gajim_optional_features:
q.addChild('feature', attrs = {'var': f})
if q.getChildren():
self.connection.send(iq)
@ -892,16 +854,9 @@ class ConnectionVcard:
def add_caps(self, p):
''' advertise our capabilities in presence stanza (xep-0115)'''
c = p.setTag('c', namespace = common.xmpp.NS_CAPS)
c.setAttr('node', 'http://gajim.org/caps')
ext = []
if not gajim.config.get('ignore_incoming_xhtml'):
ext.append('xhtml')
if gajim.config.get('outgoing_chat_state_notifactions') != 'disabled':
ext.append('cstates')
if len(ext):
c.setAttr('ext', ' '.join(ext))
c.setAttr('ver', gajim.version.split('-', 1)[0])
c.setAttr('hash', 'sha-1')
c.setAttr('node', 'http://gajim.org')
c.setAttr('ver', gajim.caps_hash)
return p
def node_to_dict(self, node):

View File

@ -44,8 +44,8 @@ class Contact:
# Capabilities; filled by caps.py/ConnectionCaps object
# every time it gets these from presence stanzas
self.caps_node = None
self.caps_ver = None
self.caps_exts = None
self.caps_hash_method = None
self.caps_hash = None
# please read xep-85 http://www.xmpp.org/extensions/xep-0085.html
# we keep track of xep85 support with the peer by three extra states:

View File

@ -2,7 +2,7 @@ docdir = '../'
datadir = '../'
version = '0.11.4.3-svn'
version = '0.11.4.4-svn'
import sys, os.path
for base in ('.', 'common'):

View File

@ -27,6 +27,7 @@ import locale
import config
from contacts import Contacts
from events import Events
import xmpp
try:
import defs
@ -164,6 +165,21 @@ else:
if system('gpg -h >/dev/null 2>&1'):
HAVE_GPG = False
gajim_identity = {'type': 'pc', 'category': 'client', 'name': 'Gajim'}
gajim_common_features = [xmpp.NS_BYTESTREAM, xmpp.NS_SI,
xmpp.NS_FILE, xmpp.NS_MUC, xmpp.NS_MUC_USER,
xmpp.NS_MUC_ADMIN, xmpp.NS_MUC_OWNER,
xmpp.NS_MUC_CONFIG, xmpp.NS_COMMANDS,
xmpp.NS_DISCO_INFO, 'ipv6', 'jabber:iq:gateway', xmpp.NS_LAST,
xmpp.NS_PRIVACY, xmpp.NS_PRIVATE, xmpp.NS_REGISTER,
xmpp.NS_VERSION, xmpp.NS_DATA, xmpp.NS_ENCRYPTED,
'msglog', 'sslc2s', 'stringprep', xmpp.NS_PING,
xmpp.NS_TIME_REVISED]
# Optional features gajim supports
gajim_optional_features = []
caps_hash = ''
def get_nick_from_jid(jid):
pos = jid.find('@')
return jid[:pos]

View File

@ -30,6 +30,8 @@ import urllib
import errno
import select
import sha
import hashlib
import base64
import sys
from encodings.punycode import punycode_encode
from encodings import idna
@ -38,7 +40,7 @@ import gajim
from i18n import Q_
from i18n import ngettext
from xmpp_stringprep import nodeprep, resourceprep, nameprep
import xmpp
if sys.platform == 'darwin':
from osx import nsapp
@ -1199,3 +1201,93 @@ def prepare_and_validate_gpg_keyID(account, jid, keyID):
keyID = 'UNKNOWN'
return keyID
def sort_identities_func(i1, i2):
cat1 = i1['category']
cat2 = i2['category']
if cat1 < cat2:
return -1
if cat1 > cat2:
return 1
if i1.has_key('type'):
type1 = i1['type']
else:
type1 = ''
if i2.has_key('type'):
type2 = i2['type']
else:
type2 = ''
if type1 < type2:
return -1
if type1 > type2:
return 1
if i1.has_key('xml:lang'):
lang1 = i1['xml:lang']
else:
lang1 = ''
if i2.has_key('xml:lang'):
lang2 = i2['xml:lang']
else:
lang2 = ''
if lang1 < lang2:
return -1
if lang1 > lang2:
return 1
return 0
def compute_caps_hash(identities, features, hash_method='sha-1'):
S = ''
identities.sort(cmp=sort_identities_func)
for i in identities:
c = i['category']
if i.has_key('type'):
type_ = i['type']
else:
type_ = ''
if i.has_key('xml:lang'):
lang = i['xml:lang']
else:
lang = ''
if i.has_key('name'):
name = i['name']
else:
name = ''
S += '%s/%s/%s/%s<' % (c, type_, lang, name)
features.sort()
for f in features:
S += '%s<' % f
if hash_method == 'sha-1':
hash = hashlib.sha1(S)
elif hash_method == 'md5':
hash = hashlib.md5(S)
else:
return ''
return base64.b64encode(hash.digest())
def update_optional_features():
gajim.gajim_optional_features = []
if gajim.config.get('publish_mood'):
gajim.gajim_optional_features.append(xmpp.NS_MOOD)
if gajim.config.get('subscribe_mood'):
gajim.gajim_optional_features.append(xmpp.NS_MOOD + '+notify')
if gajim.config.get('publish_activity'):
gajim.gajim_optional_features.append(xmpp.NS_ACTIVITY)
if gajim.config.get('subscribe_activity'):
gajim.gajim_optional_features.append(xmpp.NS_ACTIVITY + '+notify')
if gajim.config.get('publish_tune'):
gajim.gajim_optional_features.append(xmpp.NS_TUNE)
if gajim.config.get('subscribe_tune'):
gajim.gajim_optional_features.append(xmpp.NS_TUNE + '+notify')
if gajim.config.get('outgoing_chat_state_notifactions') != 'disabled':
gajim.gajim_optional_features.append(xmpp.NS_CHATSTATES)
if not gajim.config.get('ignore_incoming_xhtml'):
gajim.gajim_optional_features.append(xmpp.NS_XHTML_IM)
if gajim.HAVE_PYCRYPTO:
gajim.gajim_optional_features.append(xmpp.NS_ESESSION_INIT)
gajim.caps_hash = compute_caps_hash([gajim.gajim_identity],
gajim.gajim_common_features + gajim.gajim_optional_features)
# re-send presence with new hash
for account in gajim.connections:
connected = gajim.connections[account].connected
if connected > 1 and gajim.SHOW_LIST[connected] != 'invisible':
gajim.connections[account].change_status(gajim.SHOW_LIST[connected],
gajim.connections[account].status)

View File

@ -698,60 +698,59 @@ class Logger:
# to get that data without trying to convert it to unicode
#tmp, self.con.text_factory = self.con.text_factory, str
try:
self.cur.execute('''SELECT node, ver, ext, data FROM caps_cache;''');
self.cur.execute('SELECT hash_method, hash, data FROM caps_cache;');
except sqlite.OperationalError:
# might happen when there's no caps_cache table yet
# -- there's no data to read anyway then
#self.con.text_factory = tmp
return
#self.con.text_factory = tmp
for node, ver, ext, data in self.cur:
for hash_method, hash, data in self.cur:
# for each row: unpack the data field
# (format: (category, type, name, category, type, name, ...
# ..., 'FEAT', feature1, feature2, ...).join(' '))
# NOTE: if there's a need to do more gzip, put that to a function
data=GzipFile(fileobj=StringIO(str(data))).read().split('\0')
data = GzipFile(fileobj=StringIO(str(data))).read().split('\0')
i=0
identities=set()
features=set()
while i<(len(data)-2) and data[i]!='FEAT':
category=data[i]
type=data[i+1]
name=data[i+2]
identities.add((category,type,name))
i+=3
identities = list()
features = list()
while i < (len(data) - 3) and data[i] != 'FEAT':
category = data[i]
type_ = data[i + 1]
lang = data[i + 2]
name = data[i + 3]
identities.append({'category': category, 'type': type_,
'xml:lang': lang, 'name': name})
i += 4
i+=1
while i<len(data):
features.add(data[i])
i+=1
if not ext: ext=None # to make '' a None
while i < len(data):
features.append(data[i])
i += 1
# yield the row
yield node, ver, ext, identities, features
yield hash_method, hash, identities, features
def add_caps_entry(self, node, ver, ext, identities, features):
def add_caps_entry(self, hash_method, hash, identities, features):
data=[]
for identity in identities:
# there is no FEAT category
if identity[0]=='FEAT': return
if len(identity)<2 or not identity[2]:
data.extend((identity[0], identity[1], ''))
else:
data.extend(identity)
if identity['category'] == 'FEAT':
return
data.extend((identity.get('category'), identity.get('type', ''),
identity.get('xml:lang', ''), identity.get('name', '')))
data.append('FEAT')
data.extend(features)
data = '\0'.join(data)
# if there's a need to do more gzip, put that to a function
string = StringIO()
gzip=GzipFile(fileobj=string, mode='w')
gzip = GzipFile(fileobj=string, mode='w')
gzip.write(data)
gzip.close()
data = string.getvalue()
self.cur.execute('''
INSERT INTO caps_cache ( node, ver, ext, data )
VALUES (?, ?, ?, ?);
''', (node, ver, ext, buffer(data))) # (1) -- note above
INSERT INTO caps_cache ( hash_method, hash, data )
VALUES (?, ?, ?);
''', (hash_method, hash, buffer(data))) # (1) -- note above
try:
self.con.commit()
except sqlite.OperationalError, e:

View File

@ -180,6 +180,8 @@ class OptionsParser:
self.update_config_to_01142()
if old < [0, 11, 4, 3] and new >= [0, 11, 4, 3]:
self.update_config_to_01143()
if old < [0, 11, 4, 4] and new >= [0, 11, 4, 4]:
self.update_config_to_01144()
gajim.logger.init_vars()
gajim.config.set('version', new_version)
@ -566,3 +568,30 @@ class OptionsParser:
pass
con.close()
gajim.config.set('version', '0.11.4.3')
def update_config_to_01144(self):
back = os.getcwd()
os.chdir(logger.LOG_DB_FOLDER)
con = sqlite.connect(logger.LOG_DB_FILE)
os.chdir(back)
cur = con.cursor()
try:
cur.executescript('DROP TABLE caps_cache;')
con.commit()
except sqlite.OperationalError, e:
pass
try:
cur.executescript(
'''
CREATE TABLE caps_cache (
hash_method TEXT,
hash TEXT,
data BLOB
);
'''
)
con.commit()
except sqlite.OperationalError, e:
pass
con.close()
gajim.config.set('version', '0.11.4.4')

View File

@ -33,7 +33,7 @@ import thread
import logging
log = logging.getLogger('gajim.c.x.transports_nb')
from common import gajim
import common.gajim
USE_PYOPENSSL = False
@ -755,16 +755,16 @@ class NonBlockingTLS(PlugIn):
#tcpsock._sslContext = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
tcpsock.ssl_errnum = 0
tcpsock._sslContext.set_verify(OpenSSL.SSL.VERIFY_PEER, self._ssl_verify_callback)
cacerts = os.path.join(gajim.DATA_DIR, 'other', 'cacerts.pem')
cacerts = os.path.join(common.gajim.DATA_DIR, 'other', 'cacerts.pem')
try:
tcpsock._sslContext.load_verify_locations(cacerts)
except:
log.warning('Unable to load SSL certificats from file %s' % \
os.path.abspath(cacerts))
# load users certs
if os.path.isfile(gajim.MY_CACERTS):
if os.path.isfile(common.gajim.MY_CACERTS):
store = tcpsock._sslContext.get_cert_store()
f = open(gajim.MY_CACERTS)
f = open(common.gajim.MY_CACERTS)
lines = f.readlines()
i = 0
begin = -1
@ -779,11 +779,11 @@ class NonBlockingTLS(PlugIn):
store.add_cert(X509cert)
except OpenSSL.crypto.Error, exception_obj:
log.warning('Unable to load a certificate from file %s: %s' %\
(gajim.MY_CACERTS, exception_obj.args[0][0][2]))
(common.gajim.MY_CACERTS, exception_obj.args[0][0][2]))
except:
log.warning(
'Unknown error while loading certificate from file %s' % \
gajim.MY_CACERTS)
common.gajim.MY_CACERTS)
begin = -1
i += 1
tcpsock._sslObj = OpenSSL.SSL.Connection(tcpsock._sslContext, tcpsock._sock)

View File

@ -538,6 +538,7 @@ class PreferencesWindow:
if gajim.connections[account].pep_supported:
pep.user_send_mood(account, '')
self.on_checkbutton_toggled(widget, 'publish_mood')
helpers.update_optional_features()
def on_publish_activity_checkbutton_toggled(self, widget):
if widget.get_active() == False:
@ -545,6 +546,7 @@ class PreferencesWindow:
if gajim.connections[account].pep_supported:
pep.user_send_activity(account, '')
self.on_checkbutton_toggled(widget, 'publish_activity')
helpers.update_optional_features()
def on_publish_tune_checkbutton_toggled(self, widget):
if widget.get_active() == False:
@ -552,17 +554,21 @@ class PreferencesWindow:
if gajim.connections[account].pep_supported:
pep.user_send_tune(account, '')
self.on_checkbutton_toggled(widget, 'publish_tune')
helpers.update_optional_features()
gajim.interface.roster.enable_syncing_status_msg_from_current_music_track(
widget.get_active())
def on_subscribe_mood_checkbutton_toggled(self, widget):
self.on_checkbutton_toggled(widget, 'subscribe_mood')
helpers.update_optional_features()
def on_subscribe_activity_checkbutton_toggled(self, widget):
self.on_checkbutton_toggled(widget, 'subscribe_activity')
helpers.update_optional_features()
def on_subscribe_tune_checkbutton_toggled(self, widget):
self.on_checkbutton_toggled(widget, 'subscribe_tune')
helpers.update_optional_features()
def on_sort_by_show_checkbutton_toggled(self, widget):
self.on_checkbutton_toggled(widget, 'sort_by_show')
@ -625,6 +631,7 @@ class PreferencesWindow:
def on_xhtml_checkbutton_toggled(self, widget):
self.on_checkbutton_toggled(widget, 'ignore_incoming_xhtml')
helpers.update_optional_features()
def apply_speller(self):
for acct in gajim.connections:
@ -719,12 +726,17 @@ class PreferencesWindow:
def on_outgoing_chat_states_combobox_changed(self, widget):
active = widget.get_active()
old_value = gajim.config.get('outgoing_chat_state_notifications')
if active == 0: # all
gajim.config.set('outgoing_chat_state_notifications', 'all')
elif active == 1: # only composing
gajim.config.set('outgoing_chat_state_notifications', 'composing_only')
else: # disabled
gajim.config.set('outgoing_chat_state_notifications', 'disabled')
new_value = gajim.config.get('outgoing_chat_state_notifications')
if 'disabled' in (old_value, new_value):
# we changed from disabled to sth else or vice versa
helpers.update_optional_features()
def on_displayed_chat_states_combobox_changed(self, widget):
active = widget.get_active()

View File

@ -3106,6 +3106,8 @@ class Interface:
if gajim.config.get('autodetect_browser_mailer') or not cfg_was_read:
gtkgui_helpers.autodetect_browser_mailer()
helpers.update_optional_features()
if gajim.verbose:
gajim.log.setLevel(gajim.logging.DEBUG)
else: