1 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigPIN, ConfigText, ConfigYesNo, ConfigSubList, ConfigInteger
2 from Components.ServiceList import refreshServiceList
3 #from Screens.ChannelSelection import service_types_tv
4 from Screens.InputBox import PinInput
5 from Screens.MessageBox import MessageBox
6 from Tools.BoundFunction import boundFunction
7 from ServiceReference import ServiceReference
8 from Tools import Notifications
9 from Tools.Directories import resolveFilename, SCOPE_CONFIG
10 from Tools.Notifications import AddPopup
11 from enigma import eTimer, eServiceCenter, iServiceInformation, eServiceReference, eDVBDB
14 TYPE_SERVICE = "SERVICE"
15 TYPE_BOUQUETSERVICE = "BOUQUETSERVICE"
16 TYPE_BOUQUET = "BOUQUET"
17 LIST_BLACKLIST = "blacklist"
19 def InitParentalControl():
20 config.ParentalControl = ConfigSubsection()
21 config.ParentalControl.storeservicepin = ConfigSelection(default = "never", choices = [("never", _("never")), ("5", _("%d minutes") % 5), ("30", _("%d minutes") % 30), ("60", _("%d minutes") % 60), ("standby", _("until standby/restart"))])
22 config.ParentalControl.configured = ConfigYesNo(default = False)
23 config.ParentalControl.setuppinactive = ConfigYesNo(default = False)
24 config.ParentalControl.retries = ConfigSubsection()
25 config.ParentalControl.retries.servicepin = ConfigSubsection()
26 config.ParentalControl.retries.servicepin.tries = ConfigInteger(default = 3)
27 config.ParentalControl.retries.servicepin.time = ConfigInteger(default = 3)
28 config.ParentalControl.servicepin = ConfigSubList()
29 config.ParentalControl.servicepin.append(ConfigPIN(default = 0))
30 config.ParentalControl.age = ConfigSelection(default = "18", choices = [("0", _("No age block"))] + list((str(x), "%d+" % x) for x in range(3,19)))
31 config.ParentalControl.hideBlacklist = ConfigYesNo(default = False)
32 config.ParentalControl.config_sections = ConfigSubsection()
33 config.ParentalControl.config_sections.main_menu = ConfigYesNo(default = False)
34 config.ParentalControl.config_sections.configuration = ConfigYesNo(default = False)
35 config.ParentalControl.config_sections.timer_menu = ConfigYesNo(default = False)
36 config.ParentalControl.config_sections.plugin_browser = ConfigYesNo(default = False)
37 config.ParentalControl.config_sections.standby_menu = ConfigYesNo(default = False)
38 config.ParentalControl.config_sections.movie_list = ConfigYesNo(default = False)
39 config.ParentalControl.config_sections.context_menus = ConfigYesNo(default = False)
41 #Added for backwards compatibility with some 3rd party plugins that depend on this config
42 config.ParentalControl.servicepinactive = config.ParentalControl.configured
43 config.ParentalControl.setuppin = config.ParentalControl.servicepin[0]
44 config.ParentalControl.retries.setuppin = config.ParentalControl.retries.servicepin
45 config.ParentalControl.type = ConfigSelection(default = "blacklist", choices = [(LIST_BLACKLIST, _("blacklist"))])
47 global parentalControl
48 parentalControl = ParentalControl()
50 class ParentalControl:
52 #Do not call open on init, because bouquets are not ready at that moment
53 self.filesOpened = False
55 #This is the timer that is used to see, if the time for caching the pin is over
56 #Of course we could also work without a timer and compare the times every
57 #time we call isServicePlayable. But this might probably slow down zapping,
58 #That's why I decided to use a timer
59 self.sessionPinTimer = eTimer()
60 self.sessionPinTimer.callback.append(self.resetSessionPin)
61 self.getConfigValues()
63 def serviceMethodWrapper(self, service, method, *args):
64 #This method is used to call all functions that need a service as Parameter:
65 #It takes either a Service- Reference or a Bouquet- Reference and passes
66 #Either the service or all services contained in the bouquet to the method given
67 #That way all other functions do not need to distinguish between service and bouquet.
68 if "FROM BOUQUET" in service:
69 method( service , TYPE_BOUQUET , *args )
70 servicelist = self.readServicesFromBouquet(service,"C")
71 for ref in servicelist:
73 method( sRef , TYPE_BOUQUETSERVICE , *args )
75 ref = ServiceReference(service)
77 method( sRef , TYPE_SERVICE , *args )
79 def isProtected(self, ref):
80 if not config.ParentalControl.servicepinactive.value:
82 #Check if configuration has already been read or if the significant values have changed.
83 #If true: read the configuration
84 if self.storeServicePin != config.ParentalControl.storeservicepin.value:
85 self.getConfigValues()
86 service = ref.toCompareString()
88 info = eServiceCenter.getInstance().info(ref)
90 if path.startswith("/"):
91 if service.startswith("1:"):
92 refstr = info and info.getInfoString(ref, iServiceInformation.sServiceref)
93 service = refstr and eServiceReference(refstr).toCompareString()
94 if os.path.basename(path).startswith("."):
96 elif int(config.ParentalControl.age.value):
97 event = info and info.getEvent(ref)
98 rating = event and event.getParentalData()
99 age = rating and rating.getRating()
100 age = age and age <= 15 and age + 3 or 0
101 return (age and age >= int(config.ParentalControl.age.value)) or service and self.blacklist.has_key(service)
103 def isServicePlayable(self, ref, callback, session=None):
104 self.session = session
105 if self.isProtected(ref):
106 #Check if the session pin is cached
107 if self.sessionPinCached == True:
109 self.callback = callback
110 service = ref.toCompareString()
111 title = 'FROM BOUQUET "userbouquet.' in service and _("this bouquet is protected by a parental control pin") or _("this service is protected by a parental control pin")
113 Notifications.RemovePopup("Parental control")
116 self.PinDlg = session.openWithCallback(boundFunction(self.servicePinEntered, ref), PinInput, triesEntry=config.ParentalControl.retries.servicepin, pinList=self.getPinList(), service=ServiceReference(ref).getServiceName(), title=title, windowTitle=_("Parental control"), simple=False)
118 Notifications.AddNotificationParentalControl(boundFunction(self.servicePinEntered, ref), PinInput, triesEntry=config.ParentalControl.retries.servicepin, pinList=self.getPinList(), service=ServiceReference(ref).getServiceName(), title=title, windowTitle=_("Parental control"))
123 def protectService(self, service):
124 if not self.blacklist.has_key(service):
125 self.serviceMethodWrapper(service, self.addServiceToList, self.blacklist)
126 if config.ParentalControl.hideBlacklist.value and not self.sessionPinCached:
127 eDVBDB.getInstance().addFlag(eServiceReference(service), 2)
129 def unProtectService(self, service):
130 if self.blacklist.has_key(service):
131 self.serviceMethodWrapper(service, self.removeServiceFromList, self.blacklist)
133 def getProtectionLevel(self, service):
134 return not self.blacklist.has_key(service) and -1 or 0
136 def getConfigValues(self):
137 #Read all values from configuration
138 self.checkPinInterval = False
139 self.checkPinIntervalCancel = False
140 self.checkSessionPin = False
142 self.sessionPinCached = False
143 self.pinIntervalSeconds = 0
144 self.pinIntervalSecondsCancel = 0
146 self.storeServicePin = config.ParentalControl.storeservicepin.value
148 if self.storeServicePin == "never":
150 elif self.storeServicePin == "standby":
151 self.checkSessionPin = True
153 self.checkPinInterval = True
154 iMinutes = float(self.storeServicePin)
155 iSeconds = int(iMinutes*60)
156 self.pinIntervalSeconds = iSeconds
158 def standbyCounterCallback(self, configElement):
159 self.resetSessionPin()
161 def resetSessionPin(self):
162 #Reset the session pin, stop the timer
163 self.sessionPinCached = False
166 def getCurrentTimeStamp(self):
169 def getPinList(self):
170 return [ x.value for x in config.ParentalControl.servicepin ]
172 def setSessionPinCached(self):
173 if self.checkSessionPin == True:
174 self.sessionPinCached = True
175 if self.checkPinInterval == True:
176 self.sessionPinCached = True
177 self.sessionPinTimer.startLongTimer(self.pinIntervalSeconds)
179 def servicePinEntered(self, service, result):
181 self.setSessionPinCached()
183 self.callback(ref = service)
184 elif result == False:
185 messageText = _("The pin code you entered is wrong.")
187 self.session.open(MessageBox, messageText, MessageBox.TYPE_INFO, timeout=3)
189 AddPopup(messageText, MessageBox.TYPE_ERROR, timeout = 3)
191 def saveListToFile(self,sWhichList,vList):
192 #Replaces saveWhiteList and saveBlackList:
193 #I don't like to have two functions with identical code...
194 file = open(resolveFilename(SCOPE_CONFIG, sWhichList), 'w')
195 for sService,sType in vList.iteritems():
196 #Only Services that are selected directly and Bouqets are saved.
197 #Services that are added by a bouquet are not saved.
198 #This is the reason for the change in self.whitelist and self.blacklist
199 if TYPE_SERVICE in sType or TYPE_BOUQUET in sType:
200 file.write(str(sService) + "\n")
203 def openListFromFile(self,sWhichList):
204 #Replaces openWhiteList and openBlackList:
205 #I don't like to have two functions with identical code...
208 for x in open(resolveFilename(SCOPE_CONFIG, sWhichList ), 'r'):
210 self.serviceMethodWrapper(sPlain, self.addServiceToList, result)
215 def addServiceToList(self, service, type, vList):
216 #Replaces addWhitelistService and addBlacklistService
217 #The lists are not only lists of service references any more.
218 #They are named lists with the service as key and an array of types as value:
219 if vList.has_key(service):
220 if not type in vList[service]:
221 vList[service].append(type)
223 vList[service] = [type]
225 def removeServiceFromList(self, service, type, vList):
226 #Replaces deleteWhitelistService and deleteBlacklistService
227 if vList.has_key(service):
228 if type in vList[service]:
229 vList[service].remove(type)
230 if not vList[service]:
233 def readServicesFromBouquet(self,sBouquetSelection,formatstring):
234 #This method gives back a list of services for a given bouquet
235 from enigma import eServiceCenter, eServiceReference
236 from Screens.ChannelSelection import service_types_tv
237 serviceHandler = eServiceCenter.getInstance()
238 refstr = sBouquetSelection
239 root = eServiceReference(refstr)
240 list = serviceHandler.list(root)
242 services = list.getContent("CN", True) #(servicecomparestring, name)
246 self.saveListToFile(LIST_BLACKLIST, self.blacklist)
249 self.blacklist = self.openListFromFile(LIST_BLACKLIST)
251 if not self.filesOpened:
252 # Reset PIN cache on standby: Use StandbyCounter- Config- Callback
253 config.misc.standbyCounter.addNotifier(self.standbyCounterCallback, initial_call = False)
254 self.filesOpened = True
256 def __getattr__(self, name):
257 # This method is called if we lack a property. I'm lazy, so
258 # I load the files when someone 'hits' this code
259 if name in ('blacklist', 'whitelist'):
260 if not self.filesOpened:
262 return getattr(self, name)
263 raise AttributeError, name
265 def hideBlacklist(self):
267 if config.ParentalControl.servicepinactive.value and config.ParentalControl.storeservicepin.value != "never" and config.ParentalControl.hideBlacklist.value and not self.sessionPinCached:
268 for ref in self.blacklist:
269 if TYPE_BOUQUET not in ref:
270 eDVBDB.getInstance().addFlag(eServiceReference(ref), 2)
272 for ref in self.blacklist:
273 if TYPE_BOUQUET not in ref:
274 eDVBDB.getInstance().removeFlag(eServiceReference(ref), 2)