Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mrDoctorWho/xmpppy.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'xmpp/browser.py')
-rw-r--r--xmpp/browser.py522
1 files changed, 261 insertions, 261 deletions
diff --git a/xmpp/browser.py b/xmpp/browser.py
index db74131..5ecae1e 100644
--- a/xmpp/browser.py
+++ b/xmpp/browser.py
@@ -1,261 +1,261 @@
-## browser.py
-##
-## Copyright (C) 2004 Alexey "Snake" Nezhdanov
-##
-## This program is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 2, or (at your option)
-## any later version.
-##
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-## GNU General Public License for more details.
-
-# $Id: browser.py, v1.13 2013/11/03 alkorgun Exp $
-
-"""
-Browser module provides DISCO server framework for your application.
-This functionality can be used for very different purposes - from publishing
-software version and supported features to building of "jabber site" that users
-can navigate with their disco browsers and interact with active content.
-
-Such functionality is achieved via registering "DISCO handlers" that are
-automatically called when user requests some node of your disco tree.
-"""
-
-from dispatcher import *
-from plugin import PlugIn
-
-class Browser(PlugIn):
- """
- WARNING! This class is for components only. It will not work in client mode!
-
- Standart xmpppy class that is ancestor of PlugIn and can be attached
- to your application.
- All processing will be performed in the handlers registered in the browser
- instance. You can register any number of handlers ensuring that for each
- node/jid combination only one (or none) handler registered.
- You can register static information or the fully-blown function that will
- calculate the answer dynamically.
- Example of static info (see JEP-0030, examples 13-14):
- # cl - your xmpppy connection instance.
- b = xmpp.browser.Browser()
- b.PlugIn(cl)
- items = []
- item = {}
- item["jid"] = "catalog.shakespeare.lit"
- item["node"] = "books"
- item["name"] = "Books by and about Shakespeare"
- items.append(item)
- item = {}
- item["jid"] = "catalog.shakespeare.lit"
- item["node"] = "clothing"
- item["name"] = "Wear your literary taste with pride"
- items.append(item)
- item = {}
- item["jid"] = "catalog.shakespeare.lit"
- item["node"] = "music"
- item["name"] = "Music from the time of Shakespeare"
- items.append(item)
- info = {"ids": [], "features": []}
- b.setDiscoHandler({"items": items, "info": info})
-
- items should be a list of item elements.
- every item element can have any of these four keys: "jid", "node", "name", "action"
- info should be a dicionary and must have keys "ids" and "features".
- Both of them should be lists:
- ids is a list of dictionaries and features is a list of text strings.
- Example (see JEP-0030, examples 1-2)
- # cl - your xmpppy connection instance.
- b = xmpp.browser.Browser()
- b.PlugIn(cl)
- items = []
- ids = []
- ids.append({"category": "conference", "type": "text", "name": "Play-Specific Chatrooms"})
- ids.append({"category": "directory", "type": "chatroom", "name": "Play-Specific Chatrooms"})
- features = [
- NS_DISCO_INFO,
- NS_DISCO_ITEMS,
- NS_MUC,
- NS_REGISTER,
- NS_SEARCH,
- NS_TIME,
- NS_VERSION
- ]
- info = {"ids": ids, "features": features}
- # info["xdata"] = xmpp.protocol.DataForm() # JEP-0128
- b.setDiscoHandler({"items": [], "info": info})
- """
- def __init__(self):
- """
- Initialises internal variables. Used internally.
- """
- PlugIn.__init__(self)
- DBG_LINE = "browser"
- self._exported_methods = []
- self._handlers = {"": {}}
-
- def plugin(self, owner):
- """
- Registers it's own iq handlers in your application dispatcher instance.
- Used internally.
- """
- owner.RegisterHandler("iq", self._DiscoveryHandler, typ="get", ns=NS_DISCO_INFO)
- owner.RegisterHandler("iq", self._DiscoveryHandler, typ="get", ns=NS_DISCO_ITEMS)
-
- def plugout(self):
- """
- Unregisters browser's iq handlers from your application dispatcher instance.
- Used internally.
- """
- self._owner.UnregisterHandler("iq", self._DiscoveryHandler, typ="get", ns=NS_DISCO_INFO)
- self._owner.UnregisterHandler("iq", self._DiscoveryHandler, typ="get", ns=NS_DISCO_ITEMS)
-
- def _traversePath(self, node, jid, set=0):
- """
- Returns dictionary and key or None,None
- None - root node (w/o "node" attribute)
- /a/b/c - node
- /a/b/ - branch
- Set returns "" or None as the key
- get returns "" or None as the key or None as the dict.
- Used internally.
- """
- if jid in self._handlers:
- cur = self._handlers[jid]
- elif set:
- self._handlers[jid] = {}
- cur = self._handlers[jid]
- else:
- cur = self._handlers[""]
- if node is None:
- node = [None]
- else:
- node = node.replace("/", " /").split("/")
- for i in node:
- if i != "" and cur.has_key(i):
- cur = cur[i]
- elif set and i != "":
- cur[i] = {dict: cur, str: i}
- cur = cur[i]
- elif set or cur.has_key(""):
- return cur, ""
- else:
- return None, None
- if cur.has_key(1) or set:
- return cur, 1
- raise Exception("Corrupted data")
-
- def setDiscoHandler(self, handler, node="", jid=""):
- """
- This is the main method that you will use in this class.
- It is used to register supplied DISCO handler (or dictionary with static info)
- as handler of some disco tree branch.
- If you do not specify the node this handler will be used for all queried nodes.
- If you do not specify the jid this handler will be used for all queried JIDs.
-
- Usage:
- cl.Browser.setDiscoHandler(someDict, node, jid)
- or
- cl.Browser.setDiscoHandler(someDISCOHandler, node, jid)
- where
-
- someDict = {
- "items":[
- {"jid": "jid2", "action": "action2", "node":"node2", "name": "name2"},
- {"jid": "jid4", "node": "node4"}
- ],
- "info" :{
- "ids":[
- {"category":" category1", "type": "type1", "name": "name1"},
- {"category":" category3", "type": "type3", "name": "name3"},
- ],
- "features": ["feature1", "feature2", "feature3", "feature4"],
- "xdata": DataForm
- }
- }
-
- and/or
-
- def someDISCOHandler(session,request,TYR):
- # if TYR == "items": # returns items list of the same format as shown above
- # elif TYR == "info": # returns info dictionary of the same format as shown above
- # else: # this case is impossible for now.
- """
- self.DEBUG("Registering handler %s for \"%s\" node->%s" % (handler, jid, node), "info")
- node, key = self._traversePath(node, jid, 1)
- node[key] = handler
-
- def getDiscoHandler(self, node="", jid=""):
- """
- Returns the previously registered DISCO handler
- that is resonsible for this node/jid combination.
- Used internally.
- """
- node, key = self._traversePath(node, jid)
- if node:
- return node[key]
-
- def delDiscoHandler(self, node="", jid=""):
- """
- Unregisters DISCO handler that is resonsible for this
- node/jid combination. When handler is unregistered the branch
- is handled in the same way that it's parent branch from this moment.
- """
- node, key = self._traversePath(node, jid)
- if node:
- handler = node[key]
- del node[dict][node[str]]
- return handler
-
- def _DiscoveryHandler(self, conn, request):
- """
- Servers DISCO iq request from the remote client.
- Automatically determines the best handler to use and calls it
- (to handle the request. Used internally.
- """
- node = request.getQuerynode()
- if node:
- nodestr = node
- else:
- nodestr = "None"
- handler = self.getDiscoHandler(node, request.getTo())
- if not handler:
- self.DEBUG("No Handler for request with jid->%s node->%s ns->%s" % (request.getTo().__str__().encode("utf8"), nodestr.encode("utf8"), request.getQueryNS().encode("utf8")), "error")
- conn.send(Error(request, ERR_ITEM_NOT_FOUND))
- raise NodeProcessed()
- self.DEBUG("Handling request with jid->%s node->%s ns->%s" % (request.getTo().__str__().encode("utf8"), nodestr.encode("utf8"), request.getQueryNS().encode("utf8")), "ok")
- rep = request.buildReply("result")
- if node:
- rep.setQuerynode(node)
- q = rep.getTag("query")
- if request.getQueryNS() == NS_DISCO_ITEMS:
- # handler must return list: [{jid, action, node, name}]
- if isinstance(handler, dict):
- lst = handler["items"]
- else:
- lst = handler(conn, request, "items")
- if lst == None:
- conn.send(Error(request, ERR_ITEM_NOT_FOUND))
- raise NodeProcessed()
- for item in lst:
- q.addChild("item", item)
- elif request.getQueryNS() == NS_DISCO_INFO:
- if isinstance(handler, dict):
- dt = handler["info"]
- else:
- dt = handler(conn, request, "info")
- if dt == None:
- conn.send(Error(request, ERR_ITEM_NOT_FOUND))
- raise NodeProcessed()
- # handler must return dictionary:
- # {"ids": [{}, {}, {}, {}], "features": [fe, at, ur, es], "xdata": DataForm}
- for id in dt["ids"]:
- q.addChild("identity", id)
- for feature in dt["features"]:
- q.addChild("feature", {"var": feature})
- if dt.has_key("xdata"):
- q.addChild(node=dt["xdata"])
- conn.send(rep)
- raise NodeProcessed()
+## browser.py
+##
+## Copyright (C) 2004 Alexey "Snake" Nezhdanov
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+
+# $Id: browser.py, v1.13 2013/11/03 alkorgun Exp $
+
+"""
+Browser module provides DISCO server framework for your application.
+This functionality can be used for very different purposes - from publishing
+software version and supported features to building of "jabber site" that users
+can navigate with their disco browsers and interact with active content.
+
+Such functionality is achieved via registering "DISCO handlers" that are
+automatically called when user requests some node of your disco tree.
+"""
+
+from .dispatcher import *
+from .plugin import PlugIn
+
+class Browser(PlugIn):
+ """
+ WARNING! This class is for components only. It will not work in client mode!
+
+ Standart xmpppy class that is ancestor of PlugIn and can be attached
+ to your application.
+ All processing will be performed in the handlers registered in the browser
+ instance. You can register any number of handlers ensuring that for each
+ node/jid combination only one (or none) handler registered.
+ You can register static information or the fully-blown function that will
+ calculate the answer dynamically.
+ Example of static info (see JEP-0030, examples 13-14):
+ # cl - your xmpppy connection instance.
+ b = xmpp.browser.Browser()
+ b.PlugIn(cl)
+ items = []
+ item = {}
+ item["jid"] = "catalog.shakespeare.lit"
+ item["node"] = "books"
+ item["name"] = "Books by and about Shakespeare"
+ items.append(item)
+ item = {}
+ item["jid"] = "catalog.shakespeare.lit"
+ item["node"] = "clothing"
+ item["name"] = "Wear your literary taste with pride"
+ items.append(item)
+ item = {}
+ item["jid"] = "catalog.shakespeare.lit"
+ item["node"] = "music"
+ item["name"] = "Music from the time of Shakespeare"
+ items.append(item)
+ info = {"ids": [], "features": []}
+ b.setDiscoHandler({"items": items, "info": info})
+
+ items should be a list of item elements.
+ every item element can have any of these four keys: "jid", "node", "name", "action"
+ info should be a dicionary and must have keys "ids" and "features".
+ Both of them should be lists:
+ ids is a list of dictionaries and features is a list of text strings.
+ Example (see JEP-0030, examples 1-2)
+ # cl - your xmpppy connection instance.
+ b = xmpp.browser.Browser()
+ b.PlugIn(cl)
+ items = []
+ ids = []
+ ids.append({"category": "conference", "type": "text", "name": "Play-Specific Chatrooms"})
+ ids.append({"category": "directory", "type": "chatroom", "name": "Play-Specific Chatrooms"})
+ features = [
+ NS_DISCO_INFO,
+ NS_DISCO_ITEMS,
+ NS_MUC,
+ NS_REGISTER,
+ NS_SEARCH,
+ NS_TIME,
+ NS_VERSION
+ ]
+ info = {"ids": ids, "features": features}
+ # info["xdata"] = xmpp.protocol.DataForm() # JEP-0128
+ b.setDiscoHandler({"items": [], "info": info})
+ """
+ def __init__(self):
+ """
+ Initialises internal variables. Used internally.
+ """
+ PlugIn.__init__(self)
+ DBG_LINE = "browser"
+ self._exported_methods = []
+ self._handlers = {"": {}}
+
+ def plugin(self, owner):
+ """
+ Registers it's own iq handlers in your application dispatcher instance.
+ Used internally.
+ """
+ owner.RegisterHandler("iq", self._DiscoveryHandler, typ="get", ns=NS_DISCO_INFO)
+ owner.RegisterHandler("iq", self._DiscoveryHandler, typ="get", ns=NS_DISCO_ITEMS)
+
+ def plugout(self):
+ """
+ Unregisters browser's iq handlers from your application dispatcher instance.
+ Used internally.
+ """
+ self._owner.UnregisterHandler("iq", self._DiscoveryHandler, typ="get", ns=NS_DISCO_INFO)
+ self._owner.UnregisterHandler("iq", self._DiscoveryHandler, typ="get", ns=NS_DISCO_ITEMS)
+
+ def _traversePath(self, node, jid, set=0):
+ """
+ Returns dictionary and key or None,None
+ None - root node (w/o "node" attribute)
+ /a/b/c - node
+ /a/b/ - branch
+ Set returns "" or None as the key
+ get returns "" or None as the key or None as the dict.
+ Used internally.
+ """
+ if jid in self._handlers:
+ cur = self._handlers[jid]
+ elif set:
+ self._handlers[jid] = {}
+ cur = self._handlers[jid]
+ else:
+ cur = self._handlers[""]
+ if node is None:
+ node = [None]
+ else:
+ node = node.replace("/", " /").split("/")
+ for i in node:
+ if i != "" and i in cur:
+ cur = cur[i]
+ elif set and i != "":
+ cur[i] = {dict: cur, str: i}
+ cur = cur[i]
+ elif set or "" in cur:
+ return cur, ""
+ else:
+ return None, None
+ if 1 in cur or set:
+ return cur, 1
+ raise Exception("Corrupted data")
+
+ def setDiscoHandler(self, handler, node="", jid=""):
+ """
+ This is the main method that you will use in this class.
+ It is used to register supplied DISCO handler (or dictionary with static info)
+ as handler of some disco tree branch.
+ If you do not specify the node this handler will be used for all queried nodes.
+ If you do not specify the jid this handler will be used for all queried JIDs.
+
+ Usage:
+ cl.Browser.setDiscoHandler(someDict, node, jid)
+ or
+ cl.Browser.setDiscoHandler(someDISCOHandler, node, jid)
+ where
+
+ someDict = {
+ "items":[
+ {"jid": "jid2", "action": "action2", "node":"node2", "name": "name2"},
+ {"jid": "jid4", "node": "node4"}
+ ],
+ "info" :{
+ "ids":[
+ {"category":" category1", "type": "type1", "name": "name1"},
+ {"category":" category3", "type": "type3", "name": "name3"},
+ ],
+ "features": ["feature1", "feature2", "feature3", "feature4"],
+ "xdata": DataForm
+ }
+ }
+
+ and/or
+
+ def someDISCOHandler(session,request,TYR):
+ # if TYR == "items": # returns items list of the same format as shown above
+ # elif TYR == "info": # returns info dictionary of the same format as shown above
+ # else: # this case is impossible for now.
+ """
+ self.DEBUG("Registering handler %s for \"%s\" node->%s" % (handler, jid, node), "info")
+ node, key = self._traversePath(node, jid, 1)
+ node[key] = handler
+
+ def getDiscoHandler(self, node="", jid=""):
+ """
+ Returns the previously registered DISCO handler
+ that is resonsible for this node/jid combination.
+ Used internally.
+ """
+ node, key = self._traversePath(node, jid)
+ if node:
+ return node[key]
+
+ def delDiscoHandler(self, node="", jid=""):
+ """
+ Unregisters DISCO handler that is resonsible for this
+ node/jid combination. When handler is unregistered the branch
+ is handled in the same way that it's parent branch from this moment.
+ """
+ node, key = self._traversePath(node, jid)
+ if node:
+ handler = node[key]
+ del node[dict][node[str]]
+ return handler
+
+ def _DiscoveryHandler(self, conn, request):
+ """
+ Servers DISCO iq request from the remote client.
+ Automatically determines the best handler to use and calls it
+ (to handle the request. Used internally.
+ """
+ node = request.getQuerynode()
+ if node:
+ nodestr = node
+ else:
+ nodestr = "None"
+ handler = self.getDiscoHandler(node, request.getTo())
+ if not handler:
+ self.DEBUG("No Handler for request with jid->%s node->%s ns->%s" % (request.getTo().__str__().encode("utf8"), nodestr.encode("utf8"), request.getQueryNS().encode("utf8")), "error")
+ conn.send(Error(request, ERR_ITEM_NOT_FOUND))
+ raise NodeProcessed()
+ self.DEBUG("Handling request with jid->%s node->%s ns->%s" % (request.getTo().__str__().encode("utf8"), nodestr.encode("utf8"), request.getQueryNS().encode("utf8")), "ok")
+ rep = request.buildReply("result")
+ if node:
+ rep.setQuerynode(node)
+ q = rep.getTag("query")
+ if request.getQueryNS() == NS_DISCO_ITEMS:
+ # handler must return list: [{jid, action, node, name}]
+ if isinstance(handler, dict):
+ lst = handler["items"]
+ else:
+ lst = handler(conn, request, "items")
+ if lst == None:
+ conn.send(Error(request, ERR_ITEM_NOT_FOUND))
+ raise NodeProcessed()
+ for item in lst:
+ q.addChild("item", item)
+ elif request.getQueryNS() == NS_DISCO_INFO:
+ if isinstance(handler, dict):
+ dt = handler["info"]
+ else:
+ dt = handler(conn, request, "info")
+ if dt == None:
+ conn.send(Error(request, ERR_ITEM_NOT_FOUND))
+ raise NodeProcessed()
+ # handler must return dictionary:
+ # {"ids": [{}, {}, {}, {}], "features": [fe, at, ur, es], "xdata": DataForm}
+ for id in dt["ids"]:
+ q.addChild("identity", id)
+ for feature in dt["features"]:
+ q.addChild("feature", {"var": feature})
+ if "xdata" in dt:
+ q.addChild(node=dt["xdata"])
+ conn.send(rep)
+ raise NodeProcessed()