a033d8461ea8259fa9b95f51966796fc7931ad94
[vuplus_dvbapp-plugin] / webinterface / src / plugin.py
1 from Plugins.Plugin import PluginDescriptor
2
3 from twisted.internet import reactor
4 from twisted.web2 import server, channel, static, resource, stream, http_headers, responsecode, http
5 from twisted.python import util
6 from twisted.python.log import startLogging,discardLogs
7
8 import webif
9 import WebIfConfig  
10 import os
11
12 from Components.config import config, ConfigSubsection, ConfigInteger,ConfigYesNo
13
14 config.plugins.Webinterface = ConfigSubsection()
15 config.plugins.Webinterface.enable = ConfigYesNo(default = True)
16 config.plugins.Webinterface.port = ConfigInteger(80,limits = (1, 999))
17 config.plugins.Webinterface.includehdd = ConfigYesNo(default = False)
18
19 sessions = [ ]
20
21  
22 """
23  set DEBUG to True, if twisted should write logoutput to a file.
24  in normal console output, twisted will print only the first Traceback.
25  is this a bug in twisted or a conflict with enigma2?
26  with this option enabled, twisted will print all TB to the logfile
27  use tail -f <file> to view this log
28 """
29                         
30 DEBUG = False
31 DEBUGFILE= "/tmp/twisted.log"
32
33 # Passwordprotection Test
34 # set it only to True, if you have a patched wrapper.py
35 # see http://twistedmatrix.com/trac/ticket/2041
36 # in /usr/lib/python2.4/site-packages/twisted/web2/auth/wrapper.py
37 # The solution is to change this line
38 #       
39 #       return self.authenticate(req), seg[1:]
40 # into this
41 #       return self.authenticate(req), seg
42 PASSWORDPROTECTION = False
43 PASSWORDPROTECTION_pwd = "root"
44 PASSWORDPROTECTION_mode = "sha"; 
45 # twisted supports more than sha ('md5','md5-sess','sha')
46 # but only sha works for me, but IE 
47 # sha, Firefox=ok, Opera=ok, wget=ok, ie=not ok
48 # md5-sess, firefox=not ok, opera=not ok,wget=ok, ie=not ok
49 # md5 same as md5-sess 
50
51 def stopWebserver():
52         reactor.disconnectAll()
53
54 def restartWebserver():
55         stopWebserver()
56         startWebserver()
57
58 def startWebserver():
59         if config.plugins.Webinterface.enable.value is not True:
60                 print "not starting Werbinterface"
61                 return False
62         if DEBUG:
63                 print "start twisted logfile, writing to %s" % DEBUGFILE 
64                 import sys
65                 startLogging(open(DEBUGFILE,'w'))
66
67         class ScreenPage(resource.Resource):
68                 def __init__(self, path):
69                         self.path = path
70                         
71                         
72                 def render(self, req):
73                         global sessions
74                         if sessions == [ ]:
75                                 return http.Response(responsecode.OK, stream="please wait until enigma has booted")
76
77                         class myProducerStream(stream.ProducerStream):
78                                 closed_callback = None
79
80                                 def close(self):
81                                         if self.closed_callback:
82                                                 self.closed_callback()
83                                         stream.ProducerStream.close(self)
84
85                         if os.path.isfile(self.path):
86                                 s=myProducerStream()
87                                 webif.renderPage(s, self.path, req, sessions[0])  # login?
88                                 return http.Response(responsecode.OK,{'Content-type': http_headers.MimeType('application', 'xhtml+xml', (('charset', 'UTF-8'),))},stream=s)
89                                 #return http.Response(responsecode.OK,stream=s)
90                         else:
91                                 return http.Response(responsecode.NOT_FOUND)
92                         
93                 def locateChild(self, request, segments):
94                         path = self.path+'/'+'/'.join(segments)
95                         if path[-1:] == "/":
96                                 path += "index.html"
97                         path +=".xml"
98                         return ScreenPage(path), ()
99                         
100         class Toplevel(resource.Resource):
101                 addSlash = True
102
103                 def render(self, req):
104                         fp = open(util.sibpath(__file__, "web-data")+"/index.html")
105                         s = fp.read()
106                         fp.close()
107                         return http.Response(responsecode.OK, {'Content-type': http_headers.MimeType('text', 'html')},stream=s)
108
109                 child_web = ScreenPage(util.sibpath(__file__, "web")) # "/web/*"
110                 child_webdata = static.File(util.sibpath(__file__, "web-data")) # FIXME: web-data appears as webdata
111
112         toplevel = Toplevel()
113         if config.plugins.Webinterface.includehdd.value:
114                 toplevel.putChild("hdd",static.File("/hdd"))
115         
116         if PASSWORDPROTECTION is False:
117                 site = server.Site(toplevel)
118         else:
119                 from twisted.cred.portal import Portal
120                 from twisted.cred import checkers
121                 from twisted.web2.auth import digest, basic, wrapper
122                 from zope.interface import Interface, implements
123                 from twisted.cred import portal
124                 class IHTTPUser(Interface):
125                         pass
126
127                 class HTTPUser(object):
128                         implements(IHTTPUser)
129
130                 class HTTPAuthRealm(object):
131                         implements(portal.IRealm)
132                         def requestAvatar(self, avatarId, mind, *interfaces):
133                                 if IHTTPUser in interfaces:
134                                         return IHTTPUser, HTTPUser()
135                                 raise NotImplementedError("Only IHTTPUser interface is supported")
136
137                 portal = Portal(HTTPAuthRealm())
138                 checker = checkers.InMemoryUsernamePasswordDatabaseDontUse(root=PASSWORDPROTECTION_pwd)
139                 portal.registerChecker(checker)
140                 root = wrapper.HTTPAuthResource(toplevel,
141                                         (basic.BasicCredentialFactory('DM7025'),digest.DigestCredentialFactory(PASSWORDPROTECTION_mode,'DM7025')),
142                                         portal, (IHTTPUser,))
143                 site = server.Site(root)
144         print "[WebIf] starting Webinterface on port",config.plugins.Webinterface.port.value
145         reactor.listenTCP(config.plugins.Webinterface.port.value, channel.HTTPFactory(site))
146
147         
148 def autostart(reason, **kwargs):
149         if "session" in kwargs:
150                 global sessions
151                 sessions.append(kwargs["session"])
152                 return
153         if reason == 0:
154                 try:
155                         startWebserver()
156                 except ImportError,e:
157                         print "[WebIf] twisted not available, not starting web services",e
158                         
159 def openconfig(session, **kwargs):
160         session.openWithCallback(configCB,WebIfConfig.WebIfConfigScreen)
161
162 def configCB(result):
163         if result is True:
164                 print "[WebIf] config changed"
165                 restartWebserver()
166         else:
167                 print "[WebIf] config not changed"
168                 
169
170 def Plugins(**kwargs):
171         return [PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart),
172                     PluginDescriptor(name=_("Webinterface"), description=_("Configuration for the Webinterface"),where = [PluginDescriptor.WHERE_PLUGINMENU], icon="plugin.png",fnc = openconfig)]