diff --git a/configure.ac b/configure.ac index 6188951d274e5403a477e209cc23847758bbb318..a68e40e8bade5c2ad28aa02f9dc869763231110b 100644 --- a/configure.ac +++ b/configure.ac @@ -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) diff --git a/src/common/caps.py b/src/common/caps.py index 080c28503473e491aaa905cbc95051dd499c504d..585820e34d0e4e36de3588932d21dbdaf0346c8b 100644 --- a/src/common/caps.py +++ b/src/common/caps.py @@ -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 = {} - - # set of tuples: (category, type, name) - # (dictionaries are not hashable, so cannot be in sets) - ciself.identities = set() + ciself.hash_method = hash_method + ciself.hash = hash + + @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,20 +184,15 @@ class ConnectionCaps(object): for xmpp registered in connection_handlers.py''' # get the caps element - caps=presence.getTag('c') - if not caps: return + caps = presence.getTag('c') + if not caps: + return - node, ver=caps['node'], caps['ver'] - if node is None or ver is None: + 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 - try: - exts=caps['ext'].split(' ') - except AttributeError: - # no exts means no exts, a perfectly valid case - exts=[] - # we will put these into proper Contact object and ask # for disco... so that disco will learn how to interpret # these caps @@ -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) - diff --git a/src/common/check_paths.py b/src/common/check_paths.py index cd77e076742f664b741b68c3110b3e8a815ed3ab..970c5a4b2125b37772bf213028814a84e5f1af93 100644 --- a/src/common/check_paths.py +++ b/src/common/check_paths.py @@ -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( diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py index e7f94916ddb96c6b176ef8dd023cf4824984fb9d..342df050b4a558deff06fbcf9f9dfb3630340d1e 100644 --- a/src/common/connection_handlers.py +++ b/src/common/connection_handlers.py @@ -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): diff --git a/src/common/contacts.py b/src/common/contacts.py index 1b9937e55d2479887467aeae34e82c3c017c9886..63724c238f105486a5f4190c3cba4754ce18b8d7 100644 --- a/src/common/contacts.py +++ b/src/common/contacts.py @@ -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: diff --git a/src/common/defs.py b/src/common/defs.py index d3ddd971ff477cf924854666499a14a169ce97ca..f6a742f6009bfdfc9ba484f75e2ac159d67b9dc8 100644 --- a/src/common/defs.py +++ b/src/common/defs.py @@ -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'): diff --git a/src/common/gajim.py b/src/common/gajim.py index a758982c608c3654b8f42103c1a3b85d098ead2a..978f67c81c704a9d0a81ab8c52c0527b0050888d 100644 --- a/src/common/gajim.py +++ b/src/common/gajim.py @@ -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] diff --git a/src/common/helpers.py b/src/common/helpers.py index 2f597645e5086e43a18295c53550f411e08a8a5d..4f7efe09a29d363c2dc2d3a2656103ba1eb353e0 100644 --- a/src/common/helpers.py +++ b/src/common/helpers.py @@ -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) diff --git a/src/common/logger.py b/src/common/logger.py index bdd9a549e87328e25007e546559cfcf96f127a1a..55301be5c172cf50b1661f8a1244f7d1c0f78fbd 100644 --- a/src/common/logger.py +++ b/src/common/logger.py @@ -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: diff --git a/src/common/optparser.py b/src/common/optparser.py index c6952dfc2127fc4f901ba97eefefe64d7e74fd90..5d62f8dd716e452003c3e463d1cc5f3c9708e7e4 100644 --- a/src/common/optparser.py +++ b/src/common/optparser.py @@ -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') diff --git a/src/common/xmpp/transports_nb.py b/src/common/xmpp/transports_nb.py index 83f199a4a5784f38d101e8a9efaff4d4465240bb..8c1855808920a332b1c0c0e8bf5c32e162a06cca 100644 --- a/src/common/xmpp/transports_nb.py +++ b/src/common/xmpp/transports_nb.py @@ -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) diff --git a/src/config.py b/src/config.py index 438688136e6826a343a4015bcb5d0979ec722394..c6796f0d8187941b6eb3530146c9a2bdaaedd2f7 100644 --- a/src/config.py +++ b/src/config.py @@ -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() diff --git a/src/gajim.py b/src/gajim.py index 38e4f8d94c20ec4f59538b030016769f1554e328..1538d322b78774021d019b5444a01290a6746339 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -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: