From 189a134722e7146ceeecc61ab3338aad198c7886 Mon Sep 17 00:00:00 2001
From: Yann Leboulanger <asterix@lagaule.org>
Date: Sun, 27 Mar 2005 10:31:26 +0000
Subject: [PATCH] service discovery is now asynchronous, we can send and
 receive other messages while we browse agents (YEAH !)

---
 Core/core.py                | 73 ++++++++++++++++++++++++++++++-------
 common/jabber.py            | 36 ++----------------
 plugins/gtkgui/config.py    | 36 ++++++++++++++++++
 plugins/gtkgui/gtkgui.glade |  1 +
 plugins/gtkgui/gtkgui.py    | 33 +++++++++++++----
 5 files changed, 127 insertions(+), 52 deletions(-)

diff --git a/Core/core.py b/Core/core.py
index 5ab6c962e9..1ea0f61d00 100644
--- a/Core/core.py
+++ b/Core/core.py
@@ -1,8 +1,8 @@
 ##	core/core.py
 ##
 ## Gajim Team:
-## 	- Yann Le Boulanger <asterix@lagaule.org>
-## 	- Vincent Hanquez <tab@snarc.org>
+##		- Yann Le Boulanger <asterix@lagaule.org>
+##		- Vincent Hanquez <tab@snarc.org>
 ##		- Nikos Kouremenos <nkour@jabber.org>
 ##
 ##	Copyright (C) 2003-2005 Gajim Team
@@ -510,6 +510,55 @@ class GajimCore:
 				groups.append(group.getData())
 			self.hub.sendPlugin('ROSTER_INFO', self.connections[con], (jid, name, sub, ask, groups))
 
+	def BrowseResultCB(self, con, iq_obj):
+		identities, features, items = [], [], []
+		q = iq_obj.getTag('service')
+		if not q:
+			return identities, features, items
+		identities = [q.attrs]
+		for node in q.kids:
+			if node.getName() == 'ns':
+				features.append(node.getData())
+			else:
+				infos = node.attrs
+				infos['category'] = node.getName()
+				items.append(node.attrs)
+		jid = str(iq_obj.getFrom())
+		self.hub.sendPlugin('AGENT_INFO', self.connections[con], \
+			(jid, identities, features, items))
+
+	def DiscoverItemsCB(self, con, iq_obj):
+		qp = iq_obj.getQueryPayload()
+		items = []
+		if not qp:
+			qp = []
+		for i in qp:
+			items.append(i.attrs)
+		jid = str(iq_obj.getFrom())
+		self.hub.sendPlugin('AGENT_INFO_ITEMS', self.connections[con],\
+			(jid, items))
+
+	def DiscoverInfoCB(self, con, iq_obj):
+		# According to JEP-0030:
+		# For identity: category, name is mandatory, type is optional.
+		# For feature: var is mandatory
+		identities, features = [], []
+		qp = iq_obj.getQueryPayload()
+		if not qp:
+			qp = []
+		for i in qp:
+			if i.getName() == 'identity':
+				identities.append(i.attrs)
+			elif i.getName() == 'feature':
+				features.append(i.getAttr('var'))
+		jid = str(iq_obj.getFrom())
+		if not identities:
+			con.browseAgents(jid)
+		else:
+			self.hub.sendPlugin('AGENT_INFO_INFO', self.connections[con],\
+				(jid, identities, features))
+			con.discoverItems(jid)
+
 	def connect(self, account):
 		"""Connect and authentificate to the Jabber server"""
 		hostname = self.cfgParser.tab[account]["hostname"]
@@ -551,6 +600,12 @@ class GajimCore:
 			con.registerHandler('iq',self.vCardCB,'result')#common.jabber.NS_VCARD)
 			con.registerHandler('iq',self.rosterSetCB,'set', \
 				common.jabber.NS_ROSTER)
+			con.registerHandler('iq',self.BrowseResultCB,'result', \
+				common.jabber.NS_BROWSE)
+			con.registerHandler('iq',self.DiscoverItemsCB,'result', \
+				common.jabber.NS_P_DISC_ITEMS)
+			con.registerHandler('iq',self.DiscoverInfoCB,'result', \
+				common.jabber.NS_P_DISC_INFO)
 		try:
 			con.connect()
 		except IOError, e:
@@ -612,14 +667,7 @@ class GajimCore:
 		return list_ev
 
 	def request_infos(self, account, con, jid):
-		identities, features = con.discoverInfo(jid)
-		if not identities:
-			identities, features, items = con.browseAgents(jid)
-		else:
-			items = con.discoverItems(jid)
-		self.hub.sendPlugin('AGENT_INFO', account, (jid, identities, features, items))
-		for item in items:
-			self.request_infos(account, con, item['jid'])
+		con.discoverInfo(jid)
 
 	def read_queue(self):
 		while self.hub.queueIn.empty() == 0:
@@ -819,10 +867,9 @@ class GajimCore:
 				if con:
 					con.updateRosterItem(jid=ev[2][0], name=ev[2][1], \
 						groups=ev[2][2])
-			#('REQ_AGENTS', account, ())
+			#('REQ_AGENTS', account, jid)
 			elif ev[0] == 'REQ_AGENTS':
-				config = self.cfgParser.__getattr__(ev[1])
-				self.request_infos(ev[1], con, config['hostname'])
+				self.request_infos(ev[1], con, ev[2])
 			#('REG_AGENT_INFO', account, agent)
 			elif ev[0] == 'REG_AGENT_INFO':
 				if con:
diff --git a/common/jabber.py b/common/jabber.py
index 36015eecd7..d95c92bc0a 100644
--- a/common/jabber.py
+++ b/common/jabber.py
@@ -718,49 +718,21 @@ class Client(Connection):
     def _discover(self,ns,jid,node=None):
         iq=Iq(to=jid,type='get',query=ns)
         if node: iq.putAttr('node',node)
-        rep=self.SendAndWaitForResponse(iq)
-        if rep: ret=rep.getQueryPayload()
-        else: ret=[]
-        if not ret: ret=[]
-        return ret
+        self.send(iq)
 
     def discoverItems(self,jid,node=None):
         """ According to JEP-0030: jid is mandatory, name, node, action is optional. """
-        ret=[]
-        disco = self._discover(NS_P_DISC_ITEMS,jid,node)
-        for i in disco:
-            ret.append(i.attrs)
-        return ret
+        self._discover(NS_P_DISC_ITEMS,jid,node)
 
     def discoverInfo(self,jid,node=None):
         """ According to JEP-0030:
             For identity: category, name is mandatory, type is optional.
             For feature: var is mandatory"""
-        identities , features = [] , []
-        disco = self._discover(NS_P_DISC_INFO,jid,node)
-        for i in disco:
-            if i.getName()=='identity': identities.append(i.attrs)
-            elif i.getName()=='feature': features.append(i.getAttr('var'))
-        return identities, features
+        self._discover(NS_P_DISC_INFO,jid,node)
 
     def browseAgents(self,jid,node=None):
-        identities, features, items = [], [], []
         iq=Iq(to=jid,type='get',query=NS_BROWSE)
-        rep=self.SendAndWaitForResponse(iq)
-        if not rep:
-            return identities, features, items
-        q = rep.getTag('service')
-        if not q:
-            return identities, features, items
-        identities = [q.attrs]
-        for node in q.kids:
-            if node.getName() == 'ns':
-                features.append(node.getData())
-            else:
-                infos = node.attrs
-                infos['category'] = node.getName()
-                items.append(node.attrs)
-        return identities, features, items
+        self.send(iq)
 
 #############################################################################
 
diff --git a/plugins/gtkgui/config.py b/plugins/gtkgui/config.py
index 0932180892..8ce06ab999 100644
--- a/plugins/gtkgui/config.py
+++ b/plugins/gtkgui/config.py
@@ -1528,6 +1528,42 @@ class Service_discovery_window:
 				self.browse(child_jid)
 			child = model.iter_next(child)
 	
+	def agent_info_info(self, agent, identities, features):
+		"""When we recieve informations about an agent, but not its items"""
+		self.agent_info(agent, identities, features, [])
+
+	def agent_info_items(self, agent, items):
+		"""When we recieve items about an agent"""
+		model = self.agents_treeview.get_model()
+		iter = model.get_iter_root()
+		# We look if this agent is in the treeview
+		while (iter):
+			if agent == model.get_value(iter, 1):
+				break
+			if model.iter_has_child(iter):
+				iter = model.iter_children(iter)
+			else:
+				if not model.iter_next(iter):
+					iter = model.iter_parent(iter)
+				if iter:
+					iter = model.iter_next(iter)
+		if not iter: #If it is not, we stop
+			return
+		for item in items:
+			if not item.has_key('name'):
+				continue
+			# We look if this item is already in the treeview
+			iter_child = model.iter_children(iter)
+			while iter_child:
+				if item['jid'] == model.get_value(iter_child, 1):
+					break
+				iter_child = model.iter_next(iter_child)
+			if not iter_child: # If it is not we add it
+				iter_child = model.append(iter, (item['name'], item['jid']))
+			self.agent_infos[item['jid']] = {'identities': [item]}
+			if self.iter_is_visible(iter_child):
+				self.browse(item['jid'])
+
 	def agent_info(self, agent, identities, features, items):
 		"""When we recieve informations about an agent"""
 		model = self.agents_treeview.get_model()
diff --git a/plugins/gtkgui/gtkgui.glade b/plugins/gtkgui/gtkgui.glade
index 6f59250acf..b3aca81358 100644
--- a/plugins/gtkgui/gtkgui.glade
+++ b/plugins/gtkgui/gtkgui.glade
@@ -2354,6 +2354,7 @@
 	      <property name="enable_search">True</property>
 	      <signal name="row_activated" handler="on_agents_treeview_row_activated" last_modification_time="Tue, 01 Mar 2005 14:20:15 GMT"/>
 	      <signal name="cursor_changed" handler="on_agents_treeview_cursor_changed" last_modification_time="Tue, 01 Mar 2005 14:20:21 GMT"/>
+	      <signal name="row_expanded" handler="on_agents_treeview_row_expanded" last_modification_time="Sun, 27 Mar 2005 10:28:52 GMT"/>
 	    </widget>
 	  </child>
 	</widget>
diff --git a/plugins/gtkgui/gtkgui.py b/plugins/gtkgui/gtkgui.py
index dbb3b229bc..39eacfcffc 100644
--- a/plugins/gtkgui/gtkgui.py
+++ b/plugins/gtkgui/gtkgui.py
@@ -458,6 +458,17 @@ class plugin:
 			self.windows[account]['browser'].agent_info(array[0], array[1], \
 				array[2], array[3])
 
+	def handle_event_agent_info_items(self, account, array):
+		#('AGENT_INFO', account, (agent, items))
+		if self.windows[account].has_key('browser'):
+			self.windows[account]['browser'].agent_info_items(array[0], array[1])
+
+	def handle_event_agent_info_info(self, account, array):
+		#('AGENT_INFO', account, (agent, identities, features))
+		if self.windows[account].has_key('browser'):
+			self.windows[account]['browser'].agent_info_info(array[0], array[1], \
+				array[2])
+
 	def handle_event_reg_agent_info(self, account, array):
 		#('REG_AGENTS_INFO', account, (agent, infos))
 		if not array[1].has_key('instructions'):
@@ -607,6 +618,10 @@ class plugin:
 				self.handle_event_agents(ev[1], ev[2])
 			elif ev[0] == 'AGENT_INFO':
 				self.handle_event_agent_info(ev[1], ev[2])
+			elif ev[0] == 'AGENT_INFO_ITEMS':
+				self.handle_event_agent_info_items(ev[1], ev[2])
+			elif ev[0] == 'AGENT_INFO_INFO':
+				self.handle_event_agent_info_info(ev[1], ev[2])
 			elif ev[0] == 'REG_AGENT_INFO':
 				self.handle_event_reg_agent_info(ev[1], ev[2])
 			elif ev[0] == 'ACC_OK':
@@ -775,10 +790,11 @@ class plugin:
 		self.queueOUT = quOUT
 		self.send('REG_MESSAGE', 'gtkgui', ['ROSTER', 'WARNING', 'ERROR', \
 			'STATUS', 'NOTIFY', 'MSG', 'MSGERROR', 'SUBSCRIBED', 'UNSUBSCRIBED', \
-			'SUBSCRIBE', 'AGENTS', 'AGENT_INFO', 'REG_AGENT_INFO', 'QUIT', \
-			'ACC_OK', 'CONFIG', 'MYVCARD', 'VCARD', 'LOG_NB_LINE', 'LOG_LINE', \
-			'VISUAL', 'GC_MSG', 'GC_SUBJECT', 'BAD_PASSPHRASE', \
-			'GPG_SECRETE_KEYS', 'ROSTER_INFO', 'MSGSENT'])
+			'SUBSCRIBE', 'AGENTS', 'AGENT_INFO', 'AGENT_INFO_ITEMS', \
+			'AGENT_INFO_INFO', 'REG_AGENT_INFO', 'QUIT', 'ACC_OK', 'CONFIG', \
+			'MYVCARD', 'VCARD', 'LOG_NB_LINE', 'LOG_LINE', 'VISUAL', 'GC_MSG', \
+			'GC_SUBJECT', 'BAD_PASSPHRASE', 'GPG_SECRETE_KEYS', 'ROSTER_INFO', \
+			'MSGSENT'])
 		self.default_config = {'autopopup':1,\
 			'autopopupaway':1,\
 			'ignore_unknown_contacts':0,\
@@ -806,11 +822,14 @@ class plugin:
 			'outmsgcolor': '#0000ff',\
 			'statusmsgcolor':'#1eaa1e',\
 			'hiddenlines':'',\
-			'accounttextcolor': '#ff0000',\ #'#ffffff'
-			'accountbgcolor': '#9fdfff',\ #'#94aa8c'
+			'accounttextcolor': '#ff0000',\
+			#'#ffffff'
+			'accountbgcolor': '#9fdfff',\
+			#'#94aa8c'
 			'accountfont': 'Sans Bold 10',\
 			'grouptextcolor': '#0000ff',\
-			'groupbgcolor': '#ffffff',\ #'#eff3e7'
+			'groupbgcolor': '#ffffff',\
+			#'#eff3e7'
 			'groupfont': 'Sans Italic 10',\
 			'usertextcolor': '#000000',\
 			'userbgcolor': '#ffffff',\
-- 
GitLab