add Pluginmenu-Icon
[enigma2-plugins.git] / 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 = False)
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 startWebserver():
52         if config.plugins.Webinterface.enable.value is not True:
53                 print "not starting Werbinterface"
54                 return False
55         if DEBUG:
56                 print "start twisted logfile, writing to %s" % DEBUGFILE 
57                 import sys
58                 startLogging(sys.stdout,0)
59                 #startLogging(open(DEBUGFILE,'w'))
60
61         class ScreenPage(resource.Resource):
62                 def __init__(self, path):
63                         self.path = path
64                         
65                         
66                 def render(self, req):
67                         global sessions
68                         if sessions == [ ]:
69                                 return http.Response(responsecode.OK, stream="please wait until enigma has booted")
70
71                         class myProducerStream(stream.ProducerStream):
72                                 closed_callback = None
73
74                                 def close(self):
75                                         if self.closed_callback:
76                                                 self.closed_callback()
77                                         stream.ProducerStream.close(self)
78
79                         if os.path.isfile(self.path):
80                                 s=myProducerStream()
81                                 webif.renderPage(s, self.path, req, sessions[0])  # login?
82                                 return http.Response(responsecode.OK,stream=s)
83                         else:
84                                 return http.Response(responsecode.NOT_FOUND)
85                         
86                 def locateChild(self, request, segments):
87                         path = self.path+'/'+'/'.join(segments)
88                         if path[-1:] == "/":
89                                 path += "index.html"
90                         path +=".xml"
91                         return ScreenPage(path), ()
92                 
93         class Toplevel(resource.Resource):
94                 addSlash = True
95
96                 def render(self, req):
97                         fp = open(util.sibpath(__file__, "web-data")+"/index.html")
98                         s = fp.read()
99                         fp.close()
100                         return http.Response(responsecode.OK, {'Content-type': http_headers.MimeType('text', 'html')},stream=s)
101
102                 child_web = ScreenPage(util.sibpath(__file__, "web")) # "/web/*"
103                 child_webdata = static.File(util.sibpath(__file__, "web-data")) # FIXME: web-data appears as webdata
104
105         toplevel = Toplevel()
106         if config.plugins.Webinterface.includehdd.value:
107                 toplevel.putChild("hdd",static.File("/hdd"))
108         
109         if PASSWORDPROTECTION is False:
110                 site = server.Site(toplevel)
111         else:
112                 from twisted.cred.portal import Portal
113                 from twisted.cred import checkers
114                 from twisted.web2.auth import digest, basic, wrapper
115                 from zope.interface import Interface, implements
116                 from twisted.cred import portal
117                 class IHTTPUser(Interface):
118                         pass
119
120                 class HTTPUser(object):
121                         implements(IHTTPUser)
122
123                 class HTTPAuthRealm(object):
124                         implements(portal.IRealm)
125                         def requestAvatar(self, avatarId, mind, *interfaces):
126                                 if IHTTPUser in interfaces:
127                                         return IHTTPUser, HTTPUser()
128                                 raise NotImplementedError("Only IHTTPUser interface is supported")
129
130                 portal = Portal(HTTPAuthRealm())
131                 checker = checkers.InMemoryUsernamePasswordDatabaseDontUse(root=PASSWORDPROTECTION_pwd)
132                 portal.registerChecker(checker)
133                 root = wrapper.HTTPAuthResource(toplevel,
134                                         (basic.BasicCredentialFactory('DM7025'),digest.DigestCredentialFactory(PASSWORDPROTECTION_mode,'DM7025')),
135                                         portal, (IHTTPUser,))
136                 site = server.Site(root)
137         print "[WebIf] starting Webinterface on port",config.plugins.Webinterface.port.value
138         reactor.listenTCP(config.plugins.Webinterface.port.value, channel.HTTPFactory(site))
139
140         
141 def autostart(reason, **kwargs):
142         if "session" in kwargs:
143                 global sessions
144                 sessions.append(kwargs["session"])
145                 return
146         if reason == 0:
147                 try:
148                         startWebserver()
149                 except ImportError:
150                         print "[WebIf] twisted not available, not starting web services"
151                         
152 def openconfig(session, **kwargs):
153         session.openWithCallback(configCB,WebIfConfig.WebIfConfigScreen)
154
155 def configCB(result):
156         if result is True:
157                 print "[WebIf] config changed"
158                 # add some code here to restart twisted. ut you are warned, this ist not easy, ive tried it ;)
159         else:
160                 print "[WebIf] config not changed"
161                 
162
163 def Plugins(**kwargs):
164         return [PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart),
165                     PluginDescriptor(name=_("Webinterface"), description=_("Configuration for the Webinterface"),where = [PluginDescriptor.WHERE_PLUGINMENU], icon="plugin.png",fnc = openconfig)]