-#
-# OK, this is more than a proof of concept
-# things to improve:
-# - nicer code
-# - screens need to be defined somehow else.
-# I don't know how, yet. Probably each in an own file.
-# - more components, like the channellist
-# - better error handling
-# - use namespace parser
-
-from Screens.Screen import Screen
-from Tools.Import import my_import
+# -*- coding: UTF-8 -*-
+Version = '$Header$';
-# for our testscreen
-from Screens.InfoBarGenerics import InfoBarServiceName, InfoBarEvent, InfoBarTuner
-
-from Components.Sources.Clock import Clock
-from Components.Sources.ServiceList import ServiceList
-from WebComponents.Sources.Volume import Volume
-from WebComponents.Sources.EPG import EPG
-from WebComponents.Sources.Timer import Timer
-from WebComponents.Sources.Movie import Movie
-from WebComponents.Sources.Message import Message
-from WebComponents.Sources.PowerState import PowerState
-from WebComponents.Sources.RemoteControl import RemoteControl
-from WebComponents.Sources.Settings import Settings
+# things to improve:
+# - better error handling
+# - use namespace parser
-from WebComponents.Sources.RequestData import RequestData
-from Components.Sources.FrontendStatus import FrontendStatus
+from Tools.Import import my_import
+from Components.Sources.Source import ObsoleteSource
from Components.Converter.Converter import Converter
-
from Components.Element import Element
from xml.sax import make_parser
from xml.sax.handler import ContentHandler, feature_namespaces
+from xml.sax.saxutils import escape as escape_xml
from twisted.python import util
-import sys
-import time
-
-# prototype of the new web frontend template system.
-
-class WebScreen(Screen):
- def __init__(self, session,request):
- Screen.__init__(self, session)
- self.stand_alone = True
- self.request = request
-# a test screen
-class TestScreen(InfoBarServiceName, InfoBarEvent,InfoBarTuner, WebScreen):
- def __init__(self, session,request):
- WebScreen.__init__(self, session,request)
- InfoBarServiceName.__init__(self)
- InfoBarEvent.__init__(self)
- InfoBarTuner.__init__(self)
- self["CurrentTime"] = Clock()
-# self["TVSystem"] = Config(config.av.tvsystem)
-# self["OSDLanguage"] = Config(config.osd.language)
-# self["FirstRun"] = Config(config.misc.firstrun)
- from enigma import eServiceReference
- fav = eServiceReference('1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25) FROM BOUQUET "bouquets.tv" ORDER BY bouquet')
- self["ServiceList"] = ServiceList(fav, command_func = self.zapTo, validate_commands=False)
- self["ServiceListBrowse"] = ServiceList(fav, command_func = self.browseTo, validate_commands=False)
- self["Volume"] = Volume(session)
- self["EPGTITLE"] = EPG(session,func=EPG.TITLE)
- self["EPGSERVICE"] = EPG(session,func=EPG.SERVICE)
- self["EPGNOW"] = EPG(session,func=EPG.NOW)
- self["TimerList"] = Timer(session,func = Timer.LIST)
- self["TimerAddEventID"] = Timer(session,func = Timer.ADDBYID)
- self["TimerAdd"] = Timer(session,func = Timer.ADD)
- self["TimerDel"] = Timer(session,func = Timer.DEL)
- self["TVBrowser"] = Timer(session,func = Timer.TVBROWSER)
- self["MovieList"] = Movie(session)
- self["Volume"] = Volume(session)
- self["Message"] = Message(session)
- self["PowerState"] = PowerState(session)
- self["RemoteControl"] = RemoteControl(session)
- self["Settings"] = Settings(session)
-
+from urllib2 import quote
+from time import time
- def browseTo(self, reftobrowse):
- self["ServiceListBrowse"].root = reftobrowse
-
- def zapTo(self, reftozap):
- self.session.nav.playService(reftozap)
-
-# TODO: (really.) put screens into own files.
-class Streaming(WebScreen):
- def __init__(self, session,request):
- WebScreen.__init__(self, session,request)
- from Components.Sources.StreamService import StreamService
- self["StreamService"] = StreamService(self.session.nav)
-
-class StreamingM3U(WebScreen):
- def __init__(self, session,request):
- WebScreen.__init__(self, session,request)
- from Components.Sources.StaticText import StaticText
- from Components.Sources.Config import Config
- from Components.config import config
- self["ref"] = StaticText()
- self["localip"] = RequestData(request,what=RequestData.HOST)
-
-class GetPid(WebScreen):
- def __init__(self, session,request):
- WebScreen.__init__(self, session,request)
- from Components.Sources.StaticText import StaticText
- from enigma import iServiceInformation
- pids = self.session.nav.getCurrentService()
- if pids is not None:
- pidinfo = pids.info()
- VPID = hex(pidinfo.getInfo(iServiceInformation.sVideoPID))
- APID = hex(pidinfo.getInfo(iServiceInformation.sAudioPID))
- PPID = hex(pidinfo.getInfo(iServiceInformation.sPMTPID))
- self["pids"] = StaticText("%s,%s,%s"%(PPID.lstrip("0x"),VPID.lstrip("0x"),APID.lstrip("0x")))
- self["localip"] = RequestData(request,what=RequestData.HOST)
-
-
-# implements the 'render'-call.
-# this will act as a downstream_element, like a renderer.
+#DO NOT REMOVE THIS IMPORT
+#It IS used (dynamically)
+from WebScreens import *
+#DO NOT REMOVE THIS IMPORT
+
+from __init__ import decrypt_block
+from os import urandom
+
+global screen_cache
+screen_cache = {}
+
+# The classes and Function in File handle all ScreenPage-based requests
+# ScreenPages use enigma2 standard functionality to bring contents to a webfrontend
+#
+# Like Skins a ScreenPage can consist of several Elements and Converters
+
+#===============================================================================
+# OneTimeElement
+#
+# This is the Standard Element for Rendering a "standard" WebElement
+#===============================================================================
class OneTimeElement(Element):
def __init__(self, id):
Element.__init__(self)
self.source_id = id
- # CHECKME: is this ok performance-wise?
def handleCommand(self, args):
- if self.source_id.find(",") >=0:
+ if ',' in self.source_id:
paramlist = self.source_id.split(",")
- list={}
+ list = {}
for key in paramlist:
- arg = args.get(key, [])
- if len(arg) == 0:
- list[key] = None
- elif len(arg) == 1:
- list[key] = "".join(arg)
- elif len(arg) == 2:
+ arg = args.get(key, ())
+ Len = len(arg)
+ if Len == 0:
+ list[key] = None
+ elif Len == 1:
+ list[key] = "".join(arg)
+ elif Len == 2:
list[key] = arg[0]
self.source.handleCommand(list)
else:
- for c in args.get(self.source_id, []):
+ for c in args.get(self.source_id, ()):
self.source.handleCommand(c)
-
- def render(self, stream):
+
+ def render(self, request):
t = self.source.getHTML(self.source_id)
- stream.write(t)
+ request.write(t)
def execBegin(self):
- pass
-
+ self.suspended = False
+
def execEnd(self):
- pass
-
+ self.suspended = True
+
def onShow(self):
pass
def onHide(self):
pass
-
+
def destroy(self):
pass
+#===============================================================================
+# MacroElement
+#
+# A MacroElement helps using OneTimeElements inside a (Simple)ListFiller Loop
+#===============================================================================
+class MacroElement(OneTimeElement):
+ def __init__(self, id, macro_dict, macro_name):
+ OneTimeElement.__init__(self, id)
+ self.macro_dict = macro_dict
+ self.macro_name = macro_name
+
+ def render(self, request):
+ self.macro_dict[self.macro_name] = self.source.getHTML(self.source_id)
+
+#===============================================================================
+# StreamingElement
+#
+# In difference to an OneTimeElement a StreamingElement sends an ongoing Stream
+# of Data. The end of the Streaming is usually when the client disconnects
+#===============================================================================
class StreamingElement(OneTimeElement):
def __init__(self, id):
OneTimeElement.__init__(self, id)
- self.stream = None
+ self.request = None
def changed(self, what):
- if self.stream:
- self.render(self.stream)
+ if self.request:
+ self.render(self.request)
- def setStream(self, stream):
- self.stream = stream
+ def setRequest(self, request):
+ self.request = request
+#===============================================================================
+# ListItem
+#
# a to-be-filled list item
+#===============================================================================
class ListItem:
def __init__(self, name, filternum):
self.name = name
self.filternum = filternum
-
+
+#===============================================================================
+# ListMacroItem
+#
+# MacroItem inside a (Simple)ListFiller
+#===============================================================================
+class ListMacroItem:
+ def __init__(self, macrodict, macroname):
+ self.macrodict = macrodict
+ self.macroname = macroname
+
+
+#===============================================================================
+# TextToHTML
+#
+# Returns the String as is
+#===============================================================================
class TextToHTML(Converter):
def __init__(self, arg):
Converter.__init__(self, arg)
def getHTML(self, id):
- return self.source.text # encode & etc. here!
+ return self.source.text.replace('\xc2\x86', '').replace('\xc2\x87', '').decode("utf-8", "ignore").encode("utf-8") # encode & etc. here!
+
+#===============================================================================
+# TextToXML
+#
+# Escapes the given Text to be XML conform
+#===============================================================================
+class TextToXML(Converter):
+ def __init__(self, arg):
+ Converter.__init__(self, arg)
+
+ def getHTML(self, id):
+ return escape_xml(self.source.text).replace('\xc2\x86', '').replace('\xc2\x87', '').replace("\x19", "").replace("\x1c", "").replace("\x1e", "").decode("utf-8", "ignore").encode("utf-8")
+
+#===============================================================================
+# TextToURL
+#
+# Escapes the given Text so it can be used inside a URL
+#===============================================================================
+class TextToURL(Converter):
+ def __init__(self, arg):
+ Converter.__init__(self, arg)
+
+ def getHTML(self, id):
+ return self.source.text.replace(" ", "%20").replace("+", "%2b").replace("&", "%26").replace('\xc2\x86', '').replace('\xc2\x87', '').decode("utf-8", "ignore").encode("utf-8")
+
+#===============================================================================
+# ReturnEmptyXML
+#
+# Returns a XML only consisting of <rootElement />
+#===============================================================================
+class ReturnEmptyXML(Converter):
+ def __init__(self, arg):
+ Converter.__init__(self, arg)
+
+ def getHTML(self, id):
+ return "<rootElement />"
-# a null-output. Useful if you only want to issue a command.
+#===============================================================================
+# Null
+# Return simply NOTHING
+# Useful if you only want to issue a command.
+#===============================================================================
class Null(Converter):
def __init__(self, arg):
Converter.__init__(self, arg)
def getHTML(self, id):
return ""
+
+#===============================================================================
+# JavascriptUpdate
+#
+# Transforms a string into a javascript update pattern
+#===============================================================================
class JavascriptUpdate(Converter):
def __init__(self, arg):
Converter.__init__(self, arg)
def getHTML(self, id):
# 3c5x9, added parent. , this is because the ie loads this in a iframe. an the set is in index.html.xml
# all other will replace this in JS
- return '<script>parent.set("%s", "%s");</script>\n'%(id, self.source.text.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"'))
+ return '<script>parent.set("%s", "%s");</script>\n' % (id, self.source.text.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"').replace('\xb0', '°'))
+
+#===============================================================================
+# SimpleListFiller
+#
+# The performant 'one-dimensonial listfiller' engine (podlfe)
+#===============================================================================
+class SimpleListFiller(Converter):
+ def __init__(self, arg):
+ Converter.__init__(self, arg)
+
+ def getText(self):
+ l = self.source.simplelist
+ conv_args = self.converter_arguments
+
+ list = [ ]
+ for element in conv_args:
+ if isinstance(element, basestring):
+ list.append((element, None))
+ elif isinstance(element, ListItem):
+ list.append((element, element.filternum))
+ elif isinstance(element, ListMacroItem):
+ list.append(element.macrodict[element.macroname], None)
+ else:
+ raise Exception("neither string, ListItem nor ListMacroItem")
+
+ strlist = [ ]
+ append = strlist.append
+ for item in l:
+ if item is None:
+ item = ""
+
+ for (element, filternum) in list:
+ #filter out "non-displayable" Characters - at the very end, do it the hard way...
+ item = str(item).replace('\xc2\x86', '').replace('\xc2\x87', '').replace("\x19", "").replace("\x1c", "").replace("\x1e", "").decode("utf-8", "ignore").encode("utf-8")
+
+ if not filternum:
+ append(element)
+ elif filternum == 2:
+ append(item.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"'))
+ elif filternum == 3:
+ append(escape_xml(item))
+ elif filternum == 4:
+ append(item.replace("%", "%25").replace("+", "%2B").replace('&', '%26').replace('?', '%3f').replace(' ', '+'))
+ elif filternum == 5:
+ append(quote(item))
+ elif filternum == 6:
+ time = parseint(item) or 0
+ t = localtime(time)
+ append("%02d:%02d" % (t.tm_hour, t.tm_min))
+ elif filternum == 7:
+ time = parseint(item) or 0
+ t = localtime(time)
+ append("%d min" % (time / 60))
+ else:
+ append(item)
+ # (this will be done in c++ later!)
+ return ''.join(strlist)
+
+ text = property(getText)
+
+#===============================================================================
# the performant 'listfiller'-engine (plfe)
+#===============================================================================
class ListFiller(Converter):
def __init__(self, arg):
Converter.__init__(self, arg)
+# print "ListFiller-arg: ",arg
def getText(self):
l = self.source.list
# now build a ["string", 1, "string", 2]-styled list, with indices into the
# list to avoid lookup of item name for each entry
- lutlist = [ isinstance(element, basestring) and (element, None) or (lut[element.name], element.filternum) for element in conv_args ]
+ lutlist = [ ]
+ for element in conv_args:
+ if isinstance(element, basestring):
+ lutlist.append((element, None))
+ elif isinstance(element, ListItem):
+ lutlist.append((lut[element.name], element.filternum))
+ elif isinstance(element, ListMacroItem):
+ lutlist.append((element.macrodict[element.macroname], None))
+ else:
+ raise Exception("neither string, ListItem nor ListMacroItem")
# now, for the huge list, do:
strlist = [ ]
append = strlist.append
for item in l:
- for (element, filternum) in lutlist:
+ for (element, filternum) in lutlist:
+ #None becomes ""
+ curitem = ""
+ if filternum:
+ #filter out "non-displayable" Characters - at the very end, do it the hard way...
+ curitem = str(item[element]).replace('\xc2\x86', '').replace('\xc2\x87', '').replace("\x19", "").replace("\x1c", "").replace("\x1e", "").decode("utf-8", "ignore").encode("utf-8")
+ if curitem is None:
+ curitem = ""
+ else:
+ if element is None:
+ element = ""
+
if not filternum:
append(element)
elif filternum == 2:
- append(str(item[element]).replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"'))
+ append(curitem.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"'))
elif filternum == 3:
- append(str(item[element]).replace("&", "&").replace("<", "<").replace('"', '"').replace(">", ">"))
+ append( escape_xml( curitem ))
elif filternum == 4:
- append(str(item[element]).replace("%", "%25").replace("+", "%2B").replace('&', '%26').replace('?', '%3f').replace(' ', '+'))
+ append(curitem.replace("%", "%25").replace("+", "%2B").replace('&', '%26').replace('?', '%3f').replace(' ', '+'))
+ elif filternum == 5:
+ append(quote(curitem))
+ elif filternum == 6:
+ from time import localtime
+ time = int(float(curitem)) or 0
+ t = localtime(time)
+ append("%02d:%02d" % (t.tm_hour, t.tm_min))
+ elif filternum == 7:
+ from time import localtime
+ time = int(float(curitem)) or 0
+ t = localtime(time)
+ append("%d min" % (time / 60))
else:
- append(str(item[element]))
+ append(curitem)
# (this will be done in c++ later!)
+
return ''.join(strlist)
text = property(getText)
+#===============================================================================
+# webifHandler
+#
+# Handles the Content of a Web-Request
+# It looks up the source, instantiates the Element and Calls the Converter
+#===============================================================================
class webifHandler(ContentHandler):
- def __init__(self, session,request):
+ def __init__(self, session, request):
self.res = [ ]
self.mode = 0
self.screen = None
self.session = session
self.screens = [ ]
self.request = request
-
+ self.macros = { }
+
+ def start_element(self, attrs):
+ scr = self.screen
+
+ wsource = attrs["source"]
+
+ path = wsource.split('.')
+ while len(path) > 1:
+ scr = self.screen.getRelatedScreen(path[0])
+ if scr is None:
+ print "[webif.py] Parent Screen not found!"
+ print wsource
+ path = path[1:]
+
+ source = scr.get(path[0])
+
+ if isinstance(source, ObsoleteSource):
+ # however, if we found an "obsolete source", issue warning, and resolve the real source.
+ print "WARNING: WEBIF '%s' USES OBSOLETE SOURCE '%s', USE '%s' INSTEAD!" % (name, wsource, source.new_source)
+ print "OBSOLETE SOURCE WILL BE REMOVED %s, PLEASE UPDATE!" % (source.removal_date)
+ if source.description:
+ print source.description
+
+ wsource = source.new_source
+ else:
+ pass
+ # otherwise, use that source.
+
+ self.source = source
+ self.source_id = str(attrs.get("id", wsource))
+ self.is_streaming = "streaming" in attrs
+ self.macro_name = attrs.get("macro") or None
+
+ def end_element(self):
+ # instatiate either a StreamingElement or a OneTimeElement, depending on what's required.
+ if not self.is_streaming:
+ if self.macro_name is None:
+ c = OneTimeElement(self.source_id)
+ else:
+ c = MacroElement(self.source_id, self.macros, self.macro_name)
+ else:
+ assert self.macro_name is None
+ c = StreamingElement(self.source_id)
+
+ c.connect(self.source)
+ self.res.append(c)
+ self.screen.renderer.append(c)
+ del self.source
+
+ def start_convert(self, attrs):
+ ctype = attrs["type"]
+
+ # TODO: we need something better here
+ if ctype[:4] == "web:": # for now
+ self.converter = eval(ctype[4:])
+ else:
+ try:
+ self.converter = my_import('.'.join(("Components", "Converter", ctype))).__dict__.get(ctype)
+ except ImportError:
+ self.converter = my_import('.'.join(("Plugins", "Extensions", "WebInterface", "WebComponents", "Converter", ctype))).__dict__.get(ctype)
+ self.sub = [ ]
+
+ def end_convert(self):
+ if len(self.sub) == 1:
+ self.sub = self.sub[0]
+ c = self.converter(self.sub)
+ c.connect(self.source)
+ self.source = c
+ del self.sub
+
+ def parse_item(self, attrs):
+ if "name" in attrs:
+ filter = {"": 1, "javascript_escape": 2, "xml": 3, "uri": 4, "urlencode": 5, "time": 6, "minutes": 7}[attrs.get("filter", "")]
+ self.sub.append(ListItem(attrs["name"], filter))
+ else:
+ assert "macro" in attrs, "e2:item must have a name= or macro= attribute!"
+ self.sub.append(ListMacroItem(self.macros, attrs["macro"]))
+
def startElement(self, name, attrs):
if name == "e2:screen":
- self.screen = eval(attrs["name"])(self.session,self.request) # fixme
+ if "external_module" in attrs:
+ exec "from " + attrs["external_module"] + " import *"
+ self.screen = eval(attrs["name"])(self.session, self.request) # fixme
self.screens.append(self.screen)
return
-
+
if name[:3] == "e2:":
self.mode += 1
- tag = [' %s="%s"' %(key,val) for (key, val) in attrs.items()]
- tag.insert(0, name)
- tag.insert(0, '<')
- tag.append('>')
- tag = ''.join(tag)#.encode('utf-8')
+ tag = '<' + name + ''.join([' %s="%s"' % x for x in attrs.items()]) + '>'
+ #tag = tag.encode('utf-8')
if self.mode == 0:
self.res.append(tag)
elif self.mode == 1: # expect "<e2:element>"
assert name == "e2:element", "found %s instead of e2:element" % name
- source = attrs["source"]
- self.source_id = str(attrs.get("id", source))
- self.source = self.screen[source]
- self.is_streaming = "streaming" in attrs
+ self.start_element(attrs)
elif self.mode == 2: # expect "<e2:convert>"
if name[:3] == "e2:":
assert name == "e2:convert"
-
- ctype = attrs["type"]
-
- # TODO: we need something better here
- if ctype[:4] == "web:": # for now
- self.converter = eval(ctype[4:])
- else:
- try:
- self.converter = my_import('.'.join(["Components", "Converter", ctype])).__dict__.get(ctype)
- except ImportError:
- self.converter = my_import('.'.join(["Plugins", "Extensions", "WebInterface", "WebComponents", "Converter", ctype])).__dict__.get(ctype)
- self.sub = [ ]
+ self.start_convert(attrs)
else:
self.sub.append(tag)
elif self.mode == 3:
assert name == "e2:item", "found %s instead of e2:item!" % name
- assert "name" in attrs, "e2:item must have a name= attribute!"
- filter = {"": 1, "javascript_escape": 2, "xml": 3, "uri": 4}[attrs.get("filter", "")]
- self.sub.append(ListItem(attrs["name"], filter))
+
+ self.parse_item(attrs)
def endElement(self, name):
if name == "e2:screen":
elif self.mode == 2 and name[:3] != "e2:":
self.sub.append(tag)
elif self.mode == 2: # closed 'convert' -> sub
- if len(self.sub) == 1:
- self.sub = self.sub[0]
- c = self.converter(self.sub)
- c.connect(self.source)
- self.source = c
- del self.sub
+ self.end_convert()
elif self.mode == 1: # closed 'element'
- # instatiate either a StreamingElement or a OneTimeElement, depending on what's required.
- if not self.is_streaming:
- c = OneTimeElement(self.source_id)
- else:
- c = StreamingElement(self.source_id)
-
- c.connect(self.source)
- self.res.append(c)
- self.screen.renderer.append(c)
- del self.source
-
+ self.end_element()
if name[:3] == "e2:":
self.mode -= 1
def processingInstruction(self, target, data):
self.res.append('<?' + target + ' ' + data + '>')
-
+
def characters(self, ch):
ch = ch.encode('utf-8')
if self.mode == 0:
self.res.append(ch)
elif self.mode == 2:
self.sub.append(ch)
-
+
def startEntity(self, name):
self.res.append('&' + name + ';');
screen.doClose()
self.screens = [ ]
-def renderPage(stream, path, req, session):
-
+#===============================================================================
+# renderPage
+#
+# Creates the Handler for a Request and calls it
+# Also ensures that the Handler is finished after the Request is done
+#===============================================================================
+def renderPage(request, path, session):
# read in the template, create required screens
# we don't have persistense yet.
# if we had, this first part would only be done once.
- handler = webifHandler(session,req)
+ handler = webifHandler(session, request)
parser = make_parser()
parser.setFeature(feature_namespaces, 0)
parser.setContentHandler(handler)
parser.parse(open(util.sibpath(__file__, path)))
-
+
# by default, we have non-streaming pages
finish = True
-
+
# first, apply "commands" (aka. URL argument)
for x in handler.res:
if isinstance(x, Element):
- x.handleCommand(req.args)
+ x.handleCommand(request.args)
handler.execBegin()
# now, we have a list with static texts mixed
# with non-static Elements.
- # flatten this list, write into the stream.
+ # flatten this list, write into the request.
for x in handler.res:
if isinstance(x, Element):
if isinstance(x, StreamingElement):
finish = False
- x.setStream(stream)
- x.render(stream)
+ x.setRequest(request)
+ x.render(request)
else:
- stream.write(str(x))
-
- def ping(s):
- from twisted.internet import reactor
- s.write("\n");
- reactor.callLater(3, ping, s)
+ request.write(str(x))
# if we met a "StreamingElement", there is at least one
# element which wants to output data more than once,
# in this case, don't finish yet, don't cleanup yet,
# but instead do that when the client disconnects.
if finish:
- handler.cleanup()
- stream.finish()
- else:
- # ok.
- # you *need* something which constantly sends something in a regular interval,
- # in order to detect disconnected clients.
- # i agree that this "ping" sucks terrible, so better be sure to have something
- # similar. A "CurrentTime" is fine. Or anything that creates *some* output.
- ping(stream)
- stream.closed_callback = lambda: handler.cleanup()
+ requestFinish(handler, request)
+
+ else:
+ def requestFinishDeferred(nothing, handler, request):
+ from twisted.internet import reactor
+ reactor.callLater(0, requestFinish, handler, request)
+
+ d = request.notifyFinish()
+
+ d.addBoth( requestFinishDeferred, handler, request )
+
+#===============================================================================
+# requestFinish
+#
+# This has to be/is called at the end of every ScreenPage-based Request
+#===============================================================================
+def requestFinish(handler, request):
+ handler.cleanup()
+ request.finish()
+
+ del handler
+
+def validate_certificate(cert, key):
+ buf = decrypt_block(cert[8:], key)
+ if buf is None:
+ return None
+ return buf[36:107] + cert[139:196]
+
+def get_random():
+ try:
+ xor = lambda a,b: ''.join(chr(ord(c)^ord(d)) for c,d in zip(a,b*100))
+ random = urandom(8)
+ x = str(time())[-8:]
+ result = xor(random, x)
+
+ return result
+ except:
+ return None