Caps: querying caps disco node (no checking result yet)

This commit is contained in:
Tomasz Melcer 2007-06-27 22:32:35 +00:00
parent a1440388da
commit 744d445c55
4 changed files with 56 additions and 32 deletions

View File

@ -11,10 +11,14 @@
## GNU General Public License for more details. ## GNU General Public License for more details.
## ##
#import xmpp
#import logger #import logger
#import gajim #import gajim
from itertools import * from itertools import *
import gajim
import xmpp
import xmpp.features_nb
from meta import VerboseClassType
class CapsCache(object): class CapsCache(object):
''' This object keeps the mapping between caps data and real disco ''' This object keeps the mapping between caps data and real disco
@ -74,6 +78,7 @@ class CapsCache(object):
>>> cc[newcaps]['csn']+=chatstates # adding data as if ext was 'csn' >>> cc[newcaps]['csn']+=chatstates # adding data as if ext was 'csn'
# warning: no feature removal! # warning: no feature removal!
''' '''
__metaclass__ = VerboseClassType
def __init__(self, logger=None): def __init__(self, logger=None):
''' Create a cache for entity capabilities. ''' ''' Create a cache for entity capabilities. '''
# our containers: # our containers:
@ -89,6 +94,7 @@ class CapsCache(object):
self.__names = {} self.__names = {}
self.__cache = {} self.__cache = {}
class CacheQuery(object): class CacheQuery(object):
__metaclass__ = VerboseClassType
def __init__(cqself, proxied): def __init__(cqself, proxied):
cqself.proxied=proxied cqself.proxied=proxied
@ -98,6 +104,7 @@ class CapsCache(object):
class CacheItem(object): class CacheItem(object):
''' TODO: logging data into db ''' ''' TODO: logging data into db '''
__metaclass__ = VerboseClassType
def __init__(ciself, node, version, ext=None): def __init__(ciself, node, version, ext=None):
# cached into db # cached into db
ciself.node = node ciself.node = node
@ -105,11 +112,8 @@ class CapsCache(object):
ciself.features = set() ciself.features = set()
ciself.exts = {} ciself.exts = {}
ciself.identities = [] # set of tuples: (category, type, name)
# reported as first... important? ciself.identities = set()
ciself.category = None
ciself.type = None
ciself.name = None
ciself.cache = self ciself.cache = self
@ -121,21 +125,21 @@ class CapsCache(object):
ciself.queried = 0 ciself.queried = 0
def __iadd__(ciself, newfeature): def __iadd__(ciself, newfeature):
newfeature=self.cache.__names.setdefault(newfeature, newfeature) newfeature=self.__names.setdefault(newfeature, newfeature)
ciself.features.add(newfeature) ciself.features.add(newfeature)
def __getitem__(ciself, exts): def __getitem__(ciself, exts):
if len(ext)==0: if len(exts)==0:
return self return ciself
if len(ext)==1: if len(exts)==1:
ext=exts[0] ext=exts[0]
if ext in ciself.exts: if ext in ciself.exts:
return ciself.exts[ext] return ciself.exts[ext]
x=CacheItem(ciself.node, ciself.version, ext) x=CacheItem(ciself.node, ciself.version, ext)
ciself.exts[ext]=x ciself.exts[ext]=x
return x return x
proxied = [self] proxied = [ciself]
proxied.extend(ciself[(e,)] for e in ext) proxied.extend(ciself[(e,)] for e in exts)
return CacheQuery(proxied) return CacheQuery(proxied)
self.__CacheItem = CacheItem self.__CacheItem = CacheItem
@ -146,11 +150,11 @@ class CapsCache(object):
gajimcaps=self[(gajim, '0.11.1')] gajimcaps=self[(gajim, '0.11.1')]
gajimcaps.category='client' gajimcaps.category='client'
gajimcaps.type='pc' gajimcaps.type='pc'
gajimcaps.features=set((common.xmpp.NS_BYTESTREAM, common.xmpp.NS_SI, gajimcaps.features=set((xmpp.NS_BYTESTREAM, xmpp.NS_SI,
common.xmpp.NS_FILE, common.xmpp.NS_MUC, common.xmpp.NS_COMMANDS, xmpp.NS_FILE, xmpp.NS_MUC, xmpp.NS_COMMANDS,
common.xmpp.NS_DISCO_INFO, common.xmpp.NS_PING, common.xmpp.NS_TIME_REVISED)) xmpp.NS_DISCO_INFO, xmpp.NS_PING, xmpp.NS_TIME_REVISED))
gajimcaps['cstates'].features=set((common.xmpp.NS_CHATSTATES,)) gajimcaps['cstates'].features=set((xmpp.NS_CHATSTATES,))
gajimcaps['xhtml'].features=set((common.xmpp.NS_XHTML_IM,)) gajimcaps['xhtml'].features=set((xmpp.NS_XHTML_IM,))
# TODO: older gajim versions # TODO: older gajim versions
@ -171,33 +175,45 @@ class CapsCache(object):
node_version = caps[:2] node_version = caps[:2]
if node_version in self.__cache: if node_version in self.__cache:
return self.__cache[node_version][caps[2]] return self.__cache[node_version][caps[2]]
node, version = self.__names[caps[0]], caps[1] node, version = self.__names.setdefault(caps[0], caps[0]), caps[1]
x=self.__cache[(node, version)]=self.__CacheItem(node, version) x=self.__CacheItem(node, version)
self.__cache[(node, version)]=x
return x return x
def preload(self, connection, jid, node, ver, exts): def preload(self, con, jid, node, ver, exts):
''' Preload data about (node, ver, exts) caps using disco ''' Preload data about (node, ver, exts) caps using disco
query to jid using proper connection. Don't query if query to jid using proper connection. Don't query if
the data is already in cache. ''' the data is already in cache. '''
q=self[(node, ver, ())] q=self[(node, ver, ())]
qq=q
def callback(identities, features):
try:
qq.identities=set(
(i['category'], i['type'], i.get('name'))
for i in identities)
qq.features=set(self.__names[f] for f in features)
qq.queried=2
print 'Got features!'
print '%s/%s:' % (qq.node, qq.version)
print '%s\n%s' % (qq.identities, qq.features)
except KeyError: # improper answer, ignore
qq.queried=0
if q.queried==0: if q.queried==0:
# do query for bare node+version pair # do query for bare node+version pair
# this will create proper object # this will create proper object
q.queried=1 q.queried=1
def callback(identities, features): xmpp.features_nb.discoverInfo(con, jid, '%s#%s' % (node, ver), callback)
q.queried=2
# TODO: put features and identities
xmpp.discoverInfo(con, jid, node='%s#%s' % (node, ver), callback)
for ext in exts: for ext in exts:
qq=q[ext] qq=q[ext]
if qq.queried==0: if qq.queried==0:
# do query for node+version+ext triple # do query for node+version+ext triple
qq.queried=1 qq.queried=1
def callback(identities, features): xmpp.features_nb.discoverInfo(con, jid,
qq.queried=2 '%s#%s' % (node, ext), callback)
# TODO: put features and identities
xmpp.discoverInfo(con, jid, node='%s#%s' % (node, ext)) capscache = CapsCache()
class ConnectionCaps(object): class ConnectionCaps(object):
''' This class highly depends on that it is a part of Connection class. ''' ''' This class highly depends on that it is a part of Connection class. '''
@ -225,12 +241,12 @@ class ConnectionCaps(object):
# for disco... so that disco will learn how to interpret # for disco... so that disco will learn how to interpret
# these caps # these caps
jid=presence.getFrom() jid=str(presence.getFrom())
# start disco query... # start disco query...
gajim.capscache.preload(self, connection, jid, node, ver, exts) capscache.preload(con, jid, node, ver, exts)
contact=gajim.contacts.get_contact_from_full_jid(self, jid) contact=gajim.contacts.get_contact_from_full_jid(self.name, jid)
if contact is None: if contact is None:
return # TODO: a way to put contact not-in-roster into Contacts return # TODO: a way to put contact not-in-roster into Contacts

View File

@ -36,6 +36,7 @@ from common import gajim
from common import atom from common import atom
from common.commands import ConnectionCommands from common.commands import ConnectionCommands
from common.pubsub import ConnectionPubSub from common.pubsub import ConnectionPubSub
from common.caps import ConnectionCaps
STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd', STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
'invisible', 'error'] 'invisible', 'error']
@ -1162,7 +1163,7 @@ class ConnectionVcard:
#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...}) #('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
self.dispatch('VCARD', vcard) self.dispatch('VCARD', vcard)
class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub): class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps):
def __init__(self): def __init__(self):
ConnectionVcard.__init__(self) ConnectionVcard.__init__(self)
ConnectionBytestream.__init__(self) ConnectionBytestream.__init__(self)
@ -1982,6 +1983,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
# that defines handlers # that defines handlers
con.RegisterHandler('message', self._messageCB) con.RegisterHandler('message', self._messageCB)
con.RegisterHandler('presence', self._presenceCB) con.RegisterHandler('presence', self._presenceCB)
con.RegisterHandler('presence', self._capsPresenceCB)
con.RegisterHandler('iq', self._vCardCB, 'result', con.RegisterHandler('iq', self._vCardCB, 'result',
common.xmpp.NS_VCARD) common.xmpp.NS_VCARD)
con.RegisterHandler('iq', self._rosterSetCB, 'set', con.RegisterHandler('iq', self._rosterSetCB, 'set',

View File

@ -233,6 +233,11 @@ class Contacts:
return contacts_instances return contacts_instances
return [] return []
def get_contact_from_full_jid(self, account, jid):
'''we will split the jid into bare jid and resource part,
then get proper contact.'''
barejid, resource=jid.split('/',1)
return self.get_contact(account, barejid, resource)
def get_highest_prio_contact_from_contacts(self, contacts): def get_highest_prio_contact_from_contacts(self, contacts):
if not contacts: if not contacts:
return None return None

View File

@ -71,6 +71,7 @@ def discoverItems(disp,jid,node=None, cb=None):
cb(ret) cb(ret)
_discover(disp, NS_DISCO_ITEMS, jid, node, _on_response) _discover(disp, NS_DISCO_ITEMS, jid, node, _on_response)
# this one is
def discoverInfo(disp,jid,node=None, cb=None): def discoverInfo(disp,jid,node=None, cb=None):
""" Query remote object about info that it publishes. Returns identities and features lists.""" """ Query remote object about info that it publishes. Returns identities and features lists."""
""" According to JEP-0030: """ According to JEP-0030: