/src/disco.py

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