From 744d445c55d4025f9b0d571a1b7abdd691c7bbd5 Mon Sep 17 00:00:00 2001
From: Tomasz Melcer <liori@exroot.org>
Date: Wed, 27 Jun 2007 22:32:35 +0000
Subject: [PATCH] Caps: querying caps disco node (no checking result yet)

---
 src/common/caps.py                | 78 +++++++++++++++++++------------
 src/common/connection_handlers.py |  4 +-
 src/common/contacts.py            |  5 ++
 src/common/xmpp/features_nb.py    |  1 +
 4 files changed, 56 insertions(+), 32 deletions(-)

diff --git a/src/common/caps.py b/src/common/caps.py
index e052fc119a..4a206cf49e 100644
--- a/src/common/caps.py
+++ b/src/common/caps.py
@@ -11,10 +11,14 @@
 ## GNU General Public License for more details.
 ##
 
-#import xmpp
 #import logger
 #import gajim
 from itertools import *
+import gajim
+import xmpp
+import xmpp.features_nb
+
+from meta import VerboseClassType
 
 class CapsCache(object):
 	''' 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'
 	# warning: no feature removal!
 	'''
+	__metaclass__ = VerboseClassType
 	def __init__(self, logger=None):
 		''' Create a cache for entity capabilities. '''
 		# our containers:
@@ -89,6 +94,7 @@ class CapsCache(object):
 		self.__names = {}
 		self.__cache = {}
 		class CacheQuery(object):
+			__metaclass__ = VerboseClassType
 			def __init__(cqself, proxied):
 				cqself.proxied=proxied
 
@@ -98,6 +104,7 @@ class CapsCache(object):
 
 		class CacheItem(object):
 			''' TODO: logging data into db '''
+			__metaclass__ = VerboseClassType
 			def __init__(ciself, node, version, ext=None):
 				# cached into db
 				ciself.node = node
@@ -105,11 +112,8 @@ class CapsCache(object):
 				ciself.features = set()
 				ciself.exts = {}
 
-				ciself.identities = []
-				# reported as first... important?
-				ciself.category = None
-				ciself.type = None
-				ciself.name = None
+				# set of tuples: (category, type, name)
+				ciself.identities = set()
 
 				ciself.cache = self
 
@@ -121,21 +125,21 @@ class CapsCache(object):
 				ciself.queried = 0
 
 			def __iadd__(ciself, newfeature):
-				newfeature=self.cache.__names.setdefault(newfeature, newfeature)
+				newfeature=self.__names.setdefault(newfeature, newfeature)
 				ciself.features.add(newfeature)
 
 			def __getitem__(ciself, exts):
-				if len(ext)==0:
-					return self
-				if len(ext)==1:
+				if len(exts)==0:
+					return ciself
+				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 = [self]
-				proxied.extend(ciself[(e,)] for e in ext)
+				proxied = [ciself]
+				proxied.extend(ciself[(e,)] for e in exts)
 				return CacheQuery(proxied)
 
 		self.__CacheItem = CacheItem
@@ -146,11 +150,11 @@ class CapsCache(object):
 		gajimcaps=self[(gajim, '0.11.1')]
 		gajimcaps.category='client'
 		gajimcaps.type='pc'
-		gajimcaps.features=set((common.xmpp.NS_BYTESTREAM, common.xmpp.NS_SI,
-			common.xmpp.NS_FILE, common.xmpp.NS_MUC, common.xmpp.NS_COMMANDS,
-			common.xmpp.NS_DISCO_INFO, common.xmpp.NS_PING, common.xmpp.NS_TIME_REVISED))
-		gajimcaps['cstates'].features=set((common.xmpp.NS_CHATSTATES,))
-		gajimcaps['xhtml'].features=set((common.xmpp.NS_XHTML_IM,))
+		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
 
@@ -171,33 +175,45 @@ class CapsCache(object):
 		node_version = caps[:2]
 		if node_version in self.__cache:
 			return self.__cache[node_version][caps[2]]
-		node, version = self.__names[caps[0]], caps[1]
-		x=self.__cache[(node, version)]=self.__CacheItem(node, version)
+		node, version = self.__names.setdefault(caps[0], caps[0]), caps[1]
+		x=self.__CacheItem(node, version)
+		self.__cache[(node, version)]=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
 		query to jid using proper connection. Don't query if
 		the data is already in cache. '''
 		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:
 			# do query for bare node+version pair
 			# this will create proper object
 			q.queried=1
-			def callback(identities, features):
-				q.queried=2
-				# TODO: put features and identities
-			xmpp.discoverInfo(con, jid, node='%s#%s' % (node, ver), callback)
+			xmpp.features_nb.discoverInfo(con, jid, '%s#%s' % (node, ver), callback)
 
 		for ext in exts:
 			qq=q[ext]
 			if qq.queried==0:
 				# do query for node+version+ext triple
 				qq.queried=1
-				def callback(identities, features):
-					qq.queried=2
-					# TODO: put features and identities
-				xmpp.discoverInfo(con, jid, node='%s#%s' % (node, ext))
+				xmpp.features_nb.discoverInfo(con, jid,
+					'%s#%s' % (node, ext), callback)
+
+capscache = CapsCache()
 
 class ConnectionCaps(object):
 	''' 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
 		# these caps
 
-		jid=presence.getFrom()
+		jid=str(presence.getFrom())
 
 		# 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:
 			return	# TODO: a way to put contact not-in-roster into Contacts
 
diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py
index 32b4d2bf5b..91cbd93d40 100644
--- a/src/common/connection_handlers.py
+++ b/src/common/connection_handlers.py
@@ -36,6 +36,7 @@ from common import gajim
 from common import atom
 from common.commands import ConnectionCommands
 from common.pubsub import ConnectionPubSub
+from common.caps import ConnectionCaps
 
 STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
 	'invisible', 'error']
@@ -1162,7 +1163,7 @@ class ConnectionVcard:
 			#('VCARD', {entry1: data, entry2: {entry21: data, ...}, ...})
 			self.dispatch('VCARD', vcard)
 
-class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub):
+class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco, ConnectionCommands, ConnectionPubSub, ConnectionCaps):
 	def __init__(self):
 		ConnectionVcard.__init__(self)
 		ConnectionBytestream.__init__(self)
@@ -1982,6 +1983,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
 		# that defines handlers
 		con.RegisterHandler('message', self._messageCB)
 		con.RegisterHandler('presence', self._presenceCB)
+		con.RegisterHandler('presence', self._capsPresenceCB)
 		con.RegisterHandler('iq', self._vCardCB, 'result',
 			common.xmpp.NS_VCARD)
 		con.RegisterHandler('iq', self._rosterSetCB, 'set',
diff --git a/src/common/contacts.py b/src/common/contacts.py
index 3db62e9cae..deed88d9f1 100644
--- a/src/common/contacts.py
+++ b/src/common/contacts.py
@@ -233,6 +233,11 @@ class Contacts:
 			return contacts_instances
 		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):
 		if not contacts:
 			return None
diff --git a/src/common/xmpp/features_nb.py b/src/common/xmpp/features_nb.py
index 1bad8e29ac..0257c87388 100644
--- a/src/common/xmpp/features_nb.py
+++ b/src/common/xmpp/features_nb.py
@@ -71,6 +71,7 @@ def discoverItems(disp,jid,node=None, cb=None):
 			cb(ret)
 	_discover(disp, NS_DISCO_ITEMS, jid, node, _on_response)
 
+# this one is
 def discoverInfo(disp,jid,node=None, cb=None):
 	""" Query remote object about info that it publishes. Returns identities and features lists."""
 	""" According to JEP-0030:
-- 
GitLab