Changeset 9508
- Timestamp:
- 04/21/08 00:58:47 (4 months ago)
- Location:
- trunk
- Files:
-
- 13 modified
-
configure.ac (modified) (1 diff)
-
src/common/caps.py (modified) (8 diffs)
-
src/common/check_paths.py (modified) (1 diff)
-
src/common/connection_handlers.py (modified) (3 diffs)
-
src/common/contacts.py (modified) (1 diff)
-
src/common/defs.py (modified) (1 diff)
-
src/common/gajim.py (modified) (2 diffs)
-
src/common/helpers.py (modified) (3 diffs)
-
src/common/logger.py (modified) (3 diffs)
-
src/common/optparser.py (modified) (2 diffs)
-
src/common/xmpp/transports_nb.py (modified) (4 diffs)
-
src/config.py (modified) (7 diffs)
-
src/gajim.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/configure.ac
r9462 r9508 1 1 AC_INIT([Gajim - A Jabber Instant Messager], 2 [0.11.4. 3-svn],[http://trac.gajim.org/],[gajim])2 [0.11.4.4-svn],[http://trac.gajim.org/],[gajim]) 3 3 AC_PREREQ([2.59]) 4 4 AM_INIT_AUTOMAKE([1.8]) -
trunk/src/common/caps.py
r8926 r9508 21 21 import xmpp.features_nb 22 22 import gajim 23 import helpers 23 24 24 25 class CapsCache(object): … … 94 95 class CacheItem(object): 95 96 ''' TODO: logging data into db ''' 96 def __init__(ciself, node, version, ext=None):97 def __init__(ciself, hash_method, hash): 97 98 # cached into db 98 ciself.node = node 99 ciself.version = version 100 ciself.features = set() 101 ciself.ext = ext 102 ciself.exts = {} 103 104 # set of tuples: (category, type, name) 105 # (dictionaries are not hashable, so cannot be in sets) 106 ciself.identities = set() 99 ciself.hash_method = hash_method 100 ciself.hash = hash 101 102 @property 103 def features(): 104 def fget(self): 105 return self.getAttr('features') 106 def fset(self, value): 107 list_ = [] 108 for feature in value: 109 list_.append(self.__names.setdefault(feature, feature)) 110 self.setAttr('features', list_) 111 112 @property 113 def identities(): 114 def fget(self): 115 return self.getAttr('identities') 116 def fset(self, value): 117 list_ = [] 118 for identity in value: 119 list_.append(self.__names.setdefault(identity, identity)) 120 self.setAttr('identities', list_) 107 121 108 122 # not cached into db: … … 113 127 ciself.queried = 0 114 128 115 class CacheQuery(object):116 def __init__(cqself, proxied):117 cqself.proxied=proxied118 119 def __getattr__(cqself, obj):120 if obj!='exts': return getattr(cqself.proxied[0], obj)121 return set(chain(ci.features for ci in cqself.proxied))122 123 def __getitem__(ciself, exts):124 if not exts: # (), [], None, False, whatever125 return ciself126 if isinstance(exts, basestring):127 exts=(exts,)128 if len(exts)==1:129 ext=exts[0]130 if ext in ciself.exts:131 return ciself.exts[ext]132 x=CacheItem(ciself.node, ciself.version, ext)133 ciself.exts[ext]=x134 return x135 proxied = [ciself]136 proxied.extend(ciself[(e,)] for e in exts)137 return ciself.CacheQuery(proxied)138 139 129 def update(ciself, identities, features): 140 130 # NOTE: self refers to CapsCache object, not to CacheItem 141 self.identities=identities 142 self.features=features 143 self.logger.add_caps_entry( 144 ciself.node, ciself.version, ciself.ext, 131 ciself.identities=identities 132 ciself.features=features 133 self.logger.add_caps_entry(ciself.hash_method, ciself.hash, 145 134 identities, features) 146 135 … … 148 137 149 138 # prepopulate data which we are sure of; note: we do not log these info 150 gajimnode = 'http://gajim.org/caps' 151 152 gajimcaps=self[(gajimnode, '0.11.1')] 153 gajimcaps.category='client' 154 gajimcaps.type='pc' 155 gajimcaps.features=set((xmpp.NS_BYTESTREAM, xmpp.NS_SI, 156 xmpp.NS_FILE, xmpp.NS_MUC, xmpp.NS_COMMANDS, 157 xmpp.NS_DISCO_INFO, xmpp.NS_PING, xmpp.NS_TIME_REVISED)) 158 gajimcaps['cstates'].features=set((xmpp.NS_CHATSTATES,)) 159 gajimcaps['xhtml'].features=set((xmpp.NS_XHTML_IM,)) 160 161 # TODO: older gajim versions 139 140 gajimcaps = self[('sha-1', gajim.caps_hash)] 141 gajimcaps.identities = [gajim.gajim_identity] 142 gajimcaps.features = gajim.gajim_common_features + \ 143 gajim.gajim_optional_features 162 144 163 145 # start logging data from the net … … 167 149 # get data from logger... 168 150 if self.logger is not None: 169 for node, ver, ext, identities, features in self.logger.iter_caps_data(): 170 x=self[(node, ver, ext)] 171 x.identities=identities 172 x.features=features 173 x.queried=2 151 for hash_method, hash, identities, features in \ 152 self.logger.iter_caps_data(): 153 x = self[(hash_method, hash)] 154 x.identities = identities 155 x.features = features 156 x.queried = 2 174 157 175 158 def __getitem__(self, caps): 176 node_version = caps[:2] 177 if node_version in self.__cache: 178 return self.__cache[node_version][caps[2]] 179 node, version = self.__names.setdefault(caps[0], caps[0]), caps[1] 180 x=self.__CacheItem(node, version) 181 self.__cache[(node, version)]=x 159 if caps in self.__cache: 160 return self.__cache[caps] 161 hash_method, hash = caps[0], caps[1] 162 x = self.__CacheItem(hash_method, hash) 163 self.__cache[(hash_method, hash)] = x 182 164 return x 183 165 184 def preload(self, account, jid, node, ver, exts):166 def preload(self, con, jid, node, hash_method, hash): 185 167 ''' Preload data about (node, ver, exts) caps using disco 186 168 query to jid using proper connection. Don't query if 187 169 the data is already in cache. ''' 188 q=self[(node, ver, ())] 189 qq=q 170 q = self[(hash_method, hash)] 190 171 191 172 if q.queried==0: 192 # do query for bare node+ versionpair173 # do query for bare node+hash pair 193 174 # this will create proper object 194 175 q.queried=1 195 account.discoverInfo(jid, '%s#%s' % (node, ver)) 196 197 for ext in exts: 198 qq=q[ext] 199 if qq.queried==0: 200 # do query for node+version+ext triple 201 qq.queried=1 202 account.discoverInfo(jid, '%s#%s' % (node, ext)) 176 con.discoverInfo(jid, '%s#%s' % (node, hash)) 203 177 204 178 gajim.capscache = CapsCache(gajim.logger) … … 211 185 212 186 # get the caps element 213 caps=presence.getTag('c') 214 if not caps: return 215 216 node, ver=caps['node'], caps['ver'] 217 if node is None or ver is None: 187 caps = presence.getTag('c') 188 if not caps: 189 return 190 191 hash_method, node, hash = caps['hash'], caps['node'], caps['ver'] 192 if hash_method is None or node is None or hash is None: 218 193 # improper caps in stanza, ignoring 219 194 return 220 221 try:222 exts=caps['ext'].split(' ')223 except AttributeError:224 # no exts means no exts, a perfectly valid case225 exts=[]226 195 227 196 # we will put these into proper Contact object and ask … … 232 201 233 202 # start disco query... 234 gajim.capscache.preload(self, jid, node, ver, exts)203 gajim.capscache.preload(self, jid, node, hash_method, hash) 235 204 236 205 contact=gajim.contacts.get_contact_from_full_jid(self.name, jid) … … 241 210 242 211 # overwriting old data 243 contact.caps_node =node244 contact.caps_ ver=ver245 contact.caps_ exts=exts212 contact.caps_node = node 213 contact.caps_hash_method = hash_method 214 contact.caps_hash = hash 246 215 247 216 def _capsDiscoCB(self, jid, node, identities, features, data): 248 contact=gajim.contacts.get_contact_from_full_jid(self.name, jid) 249 if not contact: return 250 if not contact.caps_node: return # we didn't asked for that? 251 if not node.startswith(contact.caps_node+'#'): return 252 node, ext = node.split('#', 1) 253 if ext==contact.caps_ver: # this can be also version (like '0.9') 254 exts=None 255 else: 256 exts=(ext,) 217 contact = gajim.contacts.get_contact_from_full_jid(self.name, jid) 218 if not contact: 219 return 220 if not contact.caps_node: 221 return # we didn't asked for that? 222 if not node.startswith(contact.caps_node + '#'): 223 return 224 node, hash = node.split('#', 1) 225 computed_hash = helpers.compute_caps_hash(identities, features, 226 contact.caps_hash_method) 227 if computed_hash != hash: 228 # wrong hash, forget it 229 contact.caps_node = '' 230 contact.caps_hash_method = '' 231 contact.caps_hash = '' 232 return 257 233 258 234 # if we don't have this info already... 259 caps =gajim.capscache[(node, contact.caps_ver, exts)]260 if caps.queried ==2: return261 262 identities=set((i['category'], i['type'], i.get('name')) for i in identities) 235 caps = gajim.capscache[(contact.caps_hash_method, hash)] 236 if caps.queried == 2: 237 return 238 263 239 caps.update(identities, features) 264 -
trunk/src/common/check_paths.py
r9464 r9508 83 83 84 84 CREATE TABLE caps_cache ( 85 node TEXT, 86 ver TEXT, 87 ext TEXT, 85 hash_method TEXT, 86 hash TEXT, 88 87 data BLOB); 89 88 -
trunk/src/common/connection_handlers.py
r9494 r9508 668 668 iq.setAttr('id', id) 669 669 query = iq.setTag('query') 670 query.setAttr('node','http://gajim.org /caps#' + gajim.version.split('-',670 query.setAttr('node','http://gajim.org#' + gajim.version.split('-', 671 671 1)[0]) 672 672 for f in (common.xmpp.NS_BYTESTREAM, common.xmpp.NS_SI, … … 745 745 if node: 746 746 q.setAttr('node', node) 747 q.addChild('identity', attrs = {'type': 'pc', 'category': 'client', 748 'name': 'Gajim'}) 747 q.addChild('identity', attrs = gajim.gajim_identity) 749 748 extension = None 750 749 if node and node.find('#') != -1: 751 750 extension = node[node.index('#') + 1:] 752 client_version = 'http://gajim.org/caps#' + gajim.version.split('-', 753 1)[0] 751 client_version = 'http://gajim.org#' + gajim.caps_hash 754 752 755 753 if node in (None, client_version): 756 q.addChild('feature', attrs = {'var': common.xmpp.NS_BYTESTREAM}) 757 q.addChild('feature', attrs = {'var': common.xmpp.NS_SI}) 758 q.addChild('feature', attrs = {'var': common.xmpp.NS_FILE}) 759 q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC}) 760 q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC_USER}) 761 q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC_ADMIN}) 762 q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC_OWNER}) 763 q.addChild('feature', attrs = {'var': common.xmpp.NS_MUC_CONFIG}) 764 q.addChild('feature', attrs = {'var': common.xmpp.NS_COMMANDS}) 765 q.addChild('feature', attrs = {'var': common.xmpp.NS_DISCO_INFO}) 766 q.addChild('feature', attrs = {'var': 'ipv6'}) 767 q.addChild('feature', attrs = {'var': 'jabber:iq:gateway'}) 768 q.addChild('feature', attrs = {'var': common.xmpp.NS_LAST}) 769 q.addChild('feature', attrs = {'var': common.xmpp.NS_PRIVACY}) 770 q.addChild('feature', attrs = {'var': common.xmpp.NS_PRIVATE}) 771 q.addChild('feature', attrs = {'var': common.xmpp.NS_REGISTER}) 772 q.addChild('feature', attrs = {'var': common.xmpp.NS_VERSION}) 773 q.addChild('feature', attrs = {'var': common.xmpp.NS_DATA}) 774 q.addChild('feature', attrs = {'var': common.xmpp.NS_ENCRYPTED}) 775 q.addChild('feature', attrs = {'var': 'msglog'}) 776 q.addChild('feature', attrs = {'var': 'sslc2s'}) 777 q.addChild('feature', attrs = {'var': 'stringprep'}) 778 q.addChild('feature', attrs = {'var': common.xmpp.NS_PING}) 779 q.addChild('feature', attrs = {'var': common.xmpp.NS_ACTIVITY}) 780 q.addChild('feature', attrs = {'var': common.xmpp.NS_ACTIVITY + '+notify'}) 781 q.addChild('feature', attrs = {'var': common.xmpp.NS_TUNE}) 782 q.addChild('feature', attrs = {'var': common.xmpp.NS_TUNE + '+notify'}) 783 q.addChild('feature', attrs = {'var': common.xmpp.NS_MOOD}) 784 q.addChild('feature', attrs = {'var': common.xmpp.NS_MOOD + '+notify'}) 785 q.addChild('feature', attrs = {'var': common.xmpp.NS_ESESSION_INIT}) 786 787 if (node is None or extension == 'cstates') and gajim.config.get('outgoing_chat_state_notifactions') != 'disabled': 788 q.addChild('feature', attrs = {'var': common.xmpp.NS_CHATSTATES}) 789 790 if (node is None or extension == 'xhtml') and not gajim.config.get('ignore_incoming_xhtml'): 791 q.addChild('feature', attrs = {'var': common.xmpp.NS_XHTML_IM}) 792 793 if node is None: 794 q.addChild('feature', attrs = {'var': common.xmpp.NS_PING}) 795 q.addChild('feature', attrs = {'var': common.xmpp.NS_TIME_REVISED}) 754 for f in gajim.gajim_common_features: 755 q.addChild('feature', attrs = {'var': f}) 756 for f in gajim.gajim_optional_features: 757 q.addChild('feature', attrs = {'var': f}) 796 758 797 759 if q.getChildren(): … … 893 855 ''' advertise our capabilities in presence stanza (xep-0115)''' 894 856 c = p.setTag('c', namespace = common.xmpp.NS_CAPS) 895 c.setAttr('node', 'http://gajim.org/caps') 896 ext = [] 897 if not gajim.config.get('ignore_incoming_xhtml'): 898 ext.append('xhtml') 899 if gajim.config.get('outgoing_chat_state_notifactions') != 'disabled': 900 ext.append('cstates') 901 902 if len(ext): 903 c.setAttr('ext', ' '.join(ext)) 904 c.setAttr('ver', gajim.version.split('-', 1)[0]) 857 c.setAttr('hash', 'sha-1') 858 c.setAttr('node', 'http://gajim.org') 859 c.setAttr('ver', gajim.caps_hash) 905 860 return p 906 861 -
trunk/src/common/contacts.py
r9497 r9508 45 45 # every time it gets these from presence stanzas 46 46 self.caps_node = None 47 self.caps_ ver= None48 self.caps_ exts= None47 self.caps_hash_method = None 48 self.caps_hash = None 49 49 50 50 # please read xep-85 http://www.xmpp.org/extensions/xep-0085.html -
trunk/src/common/defs.py
r9462 r9508 3 3 datadir = '../' 4 4 5 version = '0.11.4. 3-svn'5 version = '0.11.4.4-svn' 6 6 7 7 import sys, os.path -
trunk/src/common/gajim.py
r9502 r9508 28 28 from contacts import Contacts 29 29 from events import Events 30 import xmpp 30 31 31 32 try: … … 164 165 if system('gpg -h >/dev/null 2>&1'): 165 166 HAVE_GPG = False 167 168 gajim_identity = {'type': 'pc', 'category': 'client', 'name': 'Gajim'} 169 gajim_common_features = [xmpp.NS_BYTESTREAM, xmpp.NS_SI, 170 xmpp.NS_FILE, xmpp.NS_MUC, xmpp.NS_MUC_USER, 171 xmpp.NS_MUC_ADMIN, xmpp.NS_MUC_OWNER, 172 xmpp.NS_MUC_CONFIG, xmpp.NS_COMMANDS, 173 xmpp.NS_DISCO_INFO, 'ipv6', 'jabber:iq:gateway', xmpp.NS_LAST, 174 xmpp.NS_PRIVACY, xmpp.NS_PRIVATE, xmpp.NS_REGISTER, 175 xmpp.NS_VERSION, xmpp.NS_DATA, xmpp.NS_ENCRYPTED, 176 'msglog', 'sslc2s', 'stringprep', xmpp.NS_PING, 177 xmpp.NS_TIME_REVISED] 178 # Optional features gajim supports 179 gajim_optional_features = [] 180 181 caps_hash = '' 166 182 167 183 def get_nick_from_jid(jid): -
trunk/src/common/helpers.py
r9488 r9508 31 31 import select 32 32 import sha 33 import hashlib 34 import base64 33 35 import sys 34 36 from encodings.punycode import punycode_encode … … 39 41 from i18n import ngettext 40 42 from xmpp_stringprep import nodeprep, resourceprep, nameprep 41 43 import xmpp 42 44 43 45 if sys.platform == 'darwin': … … 1200 1202 return keyID 1201 1203 1204 def sort_identities_func(i1, i2): 1205 cat1 = i1['category'] 1206 cat2 = i2['category'] 1207 if cat1 < cat2: 1208 return -1 1209 if cat1 > cat2: 1210 return 1 1211 if i1.has_key('type'): 1212 type1 = i1['type'] 1213 else: 1214 type1 = '' 1215 if i2.has_key('type'): 1216 type2 = i2['type'] 1217 else: 1218 type2 = '' 1219 if type1 < type2: 1220 return -1 1221 if type1 > type2: 1222 return 1 1223 if i1.has_key('xml:lang'): 1224 lang1 = i1['xml:lang'] 1225 else: 1226 lang1 = '' 1227 if i2.has_key('xml:lang'): 1228 lang2 = i2['xml:lang'] 1229 else: 1230 lang2 = '' 1231 if lang1 < lang2: 1232 return -1 1233 if lang1 > lang2: 1234 return 1 1235 return 0 1236 1237 def compute_caps_hash(identities, features, hash_method='sha-1'): 1238 S = '' 1239 identities.sort(cmp=sort_identities_func) 1240 for i in identities: 1241 c = i['category'] 1242 if i.has_key('type'): 1243 type_ = i['type'] 1244 else: 1245 type_ = '' 1246 if i.has_key('xml:lang'): 1247 lang = i['xml:lang'] 1248 else: 1249 lang = '' 1250 if i.has_key('name'): 1251 name = i['name'] 1252 else: 1253 name = '' 1254 S += '%s/%s/%s/%s<' % (c, type_, lang, name) 1255 features.sort() 1256 for f in features: 1257 S += '%s<' % f 1258 if hash_method == 'sha-1': 1259 hash = hashlib.sha1(S) 1260 elif hash_method == 'md5': 1261 hash = hashlib.md5(S) 1262 else: 1263 return '' 1264 return base64.b64encode(hash.digest()) 1265 1266 def update_optional_features(): 1267 gajim.gajim_optional_features = [] 1268 if gajim.config.get('publish_mood'): 1269 gajim.gajim_optional_features.append(xmpp.NS_MOOD) 1270 if gajim.config.get('subscribe_mood'): 1271 gajim.gajim_optional_features.append(xmpp.NS_MOOD + '+notify') 1272 if gajim.config.get('publish_activity'): 1273 gajim.gajim_optional_features.append(xmpp.NS_ACTIVITY) 1274 if gajim.config.get('subscribe_activity'): 1275 gajim.gajim_optional_features.append(xmpp.NS_ACTIVITY + '+notify') 1276 if gajim.config.get('publish_tune'): 1277 gajim.gajim_optional_features.append(xmpp.NS_TUNE) 1278 if gajim.config.get('subscribe_tune'): 1279 gajim.gajim_optional_features.append(xmpp.NS_TUNE + '+notify') 1280 if gajim.config.get('outgoing_chat_state_notifactions') != 'disabled': 1281 gajim.gajim_optional_features.append(xmpp.NS_CHATSTATES) 1282 if not gajim.config.get('ignore_incoming_xhtml'): 1283 gajim.gajim_optional_features.append(xmpp.NS_XHTML_IM) 1284 if gajim.HAVE_PYCRYPTO: 1285 gajim.gajim_optional_features.append(xmpp.NS_ESESSION_INIT) 1286 gajim.caps_hash = compute_caps_hash([gajim.gajim_identity], 1287 gajim.gajim_common_features + gajim.gajim_optional_features) 1288 # re-send presence with new hash 1289 for account in gajim.connections: 1290 connected = gajim.connections[account].connected 1291 if connected > 1 and gajim.SHOW_LIST[connected] != 'invisible': 1292 gajim.connections[account].change_status(gajim.SHOW_LIST[connected], 1293 gajim.connections[account].status) -
trunk/src/common/logger.py
r9481 r9508 699 699 #tmp, self.con.text_factory = self.con.text_factory, str 700 700 try: 701 self.cur.execute(' ''SELECT node, ver, ext, data FROM caps_cache;''');701 self.cur.execute('SELECT hash_method, hash, data FROM caps_cache;'); 702 702 except sqlite.OperationalError: 703 703 # might happen when there's no caps_cache table yet … … 706 706 return 707 707 #self.con.text_factory = tmp 708 709 for node, ver, ext, data in self.cur: 708 for hash_method, hash, data in self.cur: 710 709 # for each row: unpack the data field 711 710 # (format: (category, type, name, category, type, name, ... 712 711 # ..., 'FEAT', feature1, feature2, ...).join(' ')) 713 712 # NOTE: if there's a need to do more gzip, put that to a
