PageRenderTime 37ms CodeModel.GetById 15ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/disco.py

http://pyaimt.googlecode.com/
Python | 174 lines | 165 code | 6 blank | 3 comment | 1 complexity | 7d3a04f93ddcbe461da19470139e3244 MD5 | raw file
  1# Copyright 2004-2006 Daniel Henninger <jadestorm@nc.rr.com>
  2# Licensed for distribution under the GPL version 2, check COPYING for details
  3
  4import utils
  5from twisted.words.xish.domish import Element
  6from twisted.words.protocols.jabber.jid import internJID
  7from twisted.internet.defer import Deferred
  8from twisted.internet import reactor
  9import sys
 10import config
 11import legacy
 12from debug import LogEvent, INFO, WARN, ERROR
 13import lang
 14import globals
 15
 16
 17class ServiceDiscovery:
 18	""" Handles Service Discovery (aka DISCO) support """
 19 	 
 20	def __init__ (self, pytrans):
 21		LogEvent(INFO)
 22		self.pytrans = pytrans
 23		self.identities = {}
 24		self.features = {}
 25		self.nodes = {}
 26		self.userInfoHandlers = []
 27		self.userItemHandlers = []
 28		
 29		self.addFeature(globals.DISCO, None, config.jid)
 30		self.addFeature(globals.DISCO, None, "USER")
 31		self.pytrans.iq.addHandler(globals.DISCO, self.incomingIq, prefix=1)
 32
 33	def addIdentity(self, category, ctype, name, jid):
 34		""" Adds an identity to this JID's discovery profile. If jid == "USER" then AIM users will get this identity. """
 35		#debug.log("ServerDiscovery: Adding identity \"%r\" \"%r\" \"%r\" \"%r\"" % (category, ctype, name, jid))
 36		LogEvent(INFO)
 37		if not self.identities.has_key(jid):
 38			self.identities[jid] = []
 39		self.identities[jid].append((category, ctype, name))
 40	
 41	def addFeature(self, var, handler, jid):
 42		""" Adds a feature to this JID's discovery profile. If jid == "USER" then AIM users will get this feature. """
 43		#debug.log("ServerDiscovery: Adding feature support \"%r\" \"%r\" \"%r\"" % (var, handler, jid))
 44		LogEvent(INFO)
 45		if not self.features.has_key(jid):
 46			self.features[jid] = []
 47		self.features[jid].append(var)
 48		if handler:
 49			self.pytrans.iq.addHandler(var, handler)
 50
 51	def addNode(self, node, handler, name, jid, rootnode):
 52		""" Adds a node to this JID's discovery profile. If jid == "USER" then AIM users will get this node. """
 53		#debug.log("ServerDiscovery: Adding node item \"%r\" \"%r\" \"%r\" \"%r\" \"%r\"" % (node, handler, name, jid, rootnode))
 54		LogEvent(INFO)
 55		if not self.nodes.has_key(jid):
 56			self.nodes[jid] = {}
 57		self.nodes[jid][node] = (handler, name, rootnode)
 58
 59	def addUserItemHandler(self, handler):
 60		""" Adds an extra handler to disco items requests directed at users """
 61		LogEvent(INFO)
 62		self.userItemHandlers.append(handler)
 63
 64	def addUserInfoHandler(self, handler):
 65		""" Adds an extra handler to disco info requests directed at users """
 66		LogEvent(INFO)
 67		self.userInfoHandlers.append(handler)
 68
 69	def incomingIq(self, el):
 70		""" Decides what to do with an IQ """
 71		fro = el.getAttribute("from")
 72		to = el.getAttribute("to")
 73		ID = el.getAttribute("id")
 74		iqType = el.getAttribute("type")
 75		ulang = utils.getLang(el)
 76		try: # StringPrep
 77			froj = internJID(fro)
 78			to = internJID(to).full()
 79		except Exception, e:
 80			LogEvent(INFO, msg="Dropping IQ because of stringprep error")
 81
 82		LogEvent(INFO, msg="Looking for handler")
 83
 84		for query in el.elements():
 85			xmlns = query.uri
 86			node = query.getAttribute("node")
 87
 88			if xmlns.startswith(globals.DISCO) and node:
 89				if self.nodes.has_key(to) and self.nodes[to].has_key(node) and self.nodes[to][node][0] != None:
 90					self.nodes[to][node][0](el)
 91					return
 92				else:
 93					# If the node we're browsing wasn't found, fall through and display the root disco
 94					self.sendDiscoInfoResponse(to=fro, ID=ID, ulang=ulang, jid=to)
 95					return
 96			elif xmlns == globals.DISCO_INFO:
 97				self.sendDiscoInfoResponse(to=fro, ID=ID, ulang=ulang, jid=to)
 98				return
 99			elif xmlns == globals.DISCO_ITEMS:
100				self.sendDiscoItemsResponse(to=fro, ID=ID, ulang=ulang, jid=to)
101				return
102
103			# Still hasn't been handled
104			LogEvent(WARN, msg="Unknown Iq Request")
105			self.pytrans.iq.sendIqError(to=fro, fro=to, ID=ID, xmlns=xmlns, etype="cancel", condition="feature-not-implemented")
106
107	def sendDiscoInfoResponse(self, to, ID, ulang, jid):
108		""" Send a service discovery disco#info stanza to the given 'to'. 'jid' is the JID that was queried. """
109		LogEvent(INFO)
110		iq = Element((None, "iq"))
111		iq.attributes["type"] = "result"
112		iq.attributes["from"] = jid
113		iq.attributes["to"] = to
114		if ID:
115			iq.attributes["id"] = ID
116		query = iq.addElement("query")
117		query.attributes["xmlns"] = globals.DISCO_INFO
118		
119		searchjid = jid
120		if jid.find('@') > 0: searchjid = "USER"
121
122		# Add any identities
123		for (category, ctype, name) in self.identities.get(searchjid, []):
124			LogEvent(INFO, msg="Found identity %r %r %r" % (category, ctype, name))
125			identity = query.addElement("identity")
126			identity.attributes["category"] = category
127			identity.attributes["type"] = ctype
128			if name:
129				identity.attributes["name"] = name
130		
131		# Add any supported features
132		for var in self.features.get(searchjid, []):
133			LogEvent(INFO, msg="Found feature %r" % (var))
134			feature = query.addElement("feature")
135			feature.attributes["var"] = var
136
137		if searchjid == "USER":
138			# Add any user specific identities/features
139			for hndl in self.userInfoHandlers:
140				hndl(jid, query)
141
142		self.pytrans.send(iq)
143
144	def sendDiscoItemsResponse(self, to, ID, ulang, jid):
145		""" Send a service discovery disco#items stanza to the given 'to'. 'jid' is the JID that was queried. """
146		LogEvent(INFO)
147		iq = Element((None, "iq"))
148		iq.attributes["type"] = "result"
149		iq.attributes["from"] = jid
150		iq.attributes["to"] = to
151		if ID:
152			iq.attributes["id"] = ID
153		query = iq.addElement("query")
154		query.attributes["xmlns"] = globals.DISCO_ITEMS
155
156		searchjid = jid
157		if jid.find('@') > 0: searchjid = "USER"
158
159		for node in self.nodes.get(searchjid, []):
160			handler, name, rootnode = self.nodes[jid][node]
161			if rootnode:
162				LogEvent(INFO, msg="Found node %r" % (node))
163				name = lang.get(name, ulang)
164				item = query.addElement("item")
165				item.attributes["jid"] = jid
166				item.attributes["node"] = node
167				item.attributes["name"] = name
168
169		if searchjid == "USER":
170			# Add any user specific items
171			for hndl in self.userItemHandlers:
172				hndl(jid, query)
173		
174		self.pytrans.send(iq)