Merge branch 'bug_607_parental_control_fix' into experimental
[enigma2.git] / lib / python / Screens / ParentalControlSetup.py
1 from Screen import Screen
2 from Components.ConfigList import ConfigListScreen
3 from Components.ActionMap import NumberActionMap
4 from Components.config import config, getConfigListEntry, ConfigNothing, NoSave, ConfigPIN
5 from Components.ParentalControlList import ParentalControlEntryComponent, ParentalControlList 
6
7 from Components.Sources.StaticText import StaticText
8 from Screens.ChoiceBox import ChoiceBox
9 from Screens.MessageBox import MessageBox
10 from Screens.InputBox import PinInput
11 from Screens.ChannelSelection import service_types_tv
12 from Tools.BoundFunction import boundFunction
13 from enigma import eServiceCenter, eTimer, eServiceReference
14 from operator import itemgetter
15
16 class ProtectedScreen:
17         def __init__(self):
18                 if self.isProtected():
19                         self.onFirstExecBegin.append(boundFunction(self.session.openWithCallback, self.pinEntered, PinInput, pinList = [self.protectedWithPin()], triesEntry = self.getTriesEntry(), title = self.getPinText(), windowTitle = _("Enter pin code")))
20
21         def getTriesEntry(self):
22                 return config.ParentalControl.retries.setuppin
23
24         def getPinText(self):
25                 return _("Please enter the correct pin code")
26
27         def isProtected(self):
28                 return True
29
30         def protectedWithPin(self):
31                 return config.ParentalControl.setuppin.value
32
33         def pinEntered(self, result):
34                 if result is None:
35                         self.close()
36                 elif not result:
37                         self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)
38
39 class ParentalControlSetup(Screen, ConfigListScreen, ProtectedScreen):
40         def __init__(self, session):
41                 Screen.__init__(self, session)
42                 ProtectedScreen.__init__(self)
43                 # for the skin: first try ParentalControlSetup, then Setup, this allows individual skinning
44                 self.skinName = ["ParentalControlSetup", "Setup" ]
45                 self.setup_title = _("Parental control setup")
46                 self.onChangedEntry = [ ]
47
48                 self.list = []
49                 ConfigListScreen.__init__(self, self.list, session = self.session, on_change = self.changedEntry)
50                 self.createSetup()
51                 
52                 self["actions"] = NumberActionMap(["SetupActions"],
53                 {
54                   "cancel": self.keyCancel,
55                   "save": self.keyCancel
56                 }, -2)
57                 self["key_red"] = StaticText(_("Cancel"))
58                 self["key_green"] = StaticText(_("OK"))
59                 self.onLayoutFinish.append(self.layoutFinished)
60
61         def layoutFinished(self):
62                 self.setTitle(self.setup_title)
63
64         def isProtected(self):
65                 return config.ParentalControl.setuppinactive.value and config.ParentalControl.configured.value
66         
67         def createSetup(self):
68                 self.editListEntry = None
69                 self.changePin = None
70                 self.changeSetupPin = None
71                 
72                 self.list = []
73                 self.list.append(getConfigListEntry(_("Enable parental control"), config.ParentalControl.configured))
74                 print "config.ParentalControl.configured.value", config.ParentalControl.configured.value
75                 self.editBouquetListEntry = -1
76                 self.reloadLists = -1
77                 if config.ParentalControl.configured.value:
78                         #self.list.append(getConfigListEntry(_("Configuration mode"), config.ParentalControl.mode))
79                         self.list.append(getConfigListEntry(_("Protect setup"), config.ParentalControl.setuppinactive))
80                         if config.ParentalControl.setuppinactive.value:
81                                 self.changeSetupPin = getConfigListEntry(_("Change setup PIN"), NoSave(ConfigNothing()))
82                                 self.list.append(self.changeSetupPin)
83                         self.list.append(getConfigListEntry(_("Protect services"), config.ParentalControl.servicepinactive))
84                         if config.ParentalControl.servicepinactive.value:
85                                 self.list.append(getConfigListEntry(_("Parental control type"), config.ParentalControl.type))
86                                 if config.ParentalControl.mode.value == "complex":
87                                         self.changePin = getConfigListEntry(_("Change service PINs"), NoSave(ConfigNothing()))
88                                         self.list.append(self.changePin)
89                                 elif config.ParentalControl.mode.value == "simple":     
90                                         self.changePin = getConfigListEntry(_("Change service PIN"), NoSave(ConfigNothing()))
91                                         self.list.append(self.changePin)
92                                 #Added Option to remember the service pin
93                                 self.list.append(getConfigListEntry(_("Remember service PIN"), config.ParentalControl.storeservicepin)) 
94                                 #Added Option to remember the cancellation of service pin entry
95                                 self.list.append(getConfigListEntry(_("Remember service PIN cancel"), config.ParentalControl.storeservicepincancel))    
96                                 self.editListEntry = getConfigListEntry(_("Edit services list"), NoSave(ConfigNothing()))
97                                 self.list.append(self.editListEntry)
98                                 #New funtion: Possibility to add Bouquets to whitelist / blacklist
99                                 self.editBouquetListEntry = getConfigListEntry(_("Edit bouquets list"), NoSave(ConfigNothing()))
100                                 self.list.append(self.editBouquetListEntry)
101                                 #New option to reload service lists (for example if bouquets have changed)
102                                 self.reloadLists = getConfigListEntry(_("Reload Black-/Whitelists"), NoSave(ConfigNothing()))
103                                 self.list.append(self.reloadLists)
104                                 
105                 self["config"].list = self.list
106                 self["config"].setList(self.list)
107
108         def keyOK(self):
109                 print "self[\"config\"].l.getCurrentSelection()", self["config"].l.getCurrentSelection()
110                 if self["config"].l.getCurrentSelection() == self.editListEntry:
111                         self.session.open(ParentalControlEditor)
112                 elif self["config"].l.getCurrentSelection() == self.editBouquetListEntry:
113                         self.session.open(ParentalControlBouquetEditor)
114                 elif self["config"].l.getCurrentSelection() == self.changePin:
115                         if config.ParentalControl.mode.value == "complex":
116                                 pass
117                         else:
118                                 self.session.open(ParentalControlChangePin, config.ParentalControl.servicepin[0], _("service PIN"))
119                 elif self["config"].l.getCurrentSelection() == self.changeSetupPin:
120                         self.session.open(ParentalControlChangePin, config.ParentalControl.setuppin, _("setup PIN"))
121                 elif self["config"].l.getCurrentSelection() == self.reloadLists:
122                         from Components.ParentalControl import parentalControl
123                         parentalControl.open()
124                 else:
125                         ConfigListScreen.keyRight(self)
126                         print "current selection:", self["config"].l.getCurrentSelection()
127                         self.createSetup()
128
129         def keyLeft(self):
130                 ConfigListScreen.keyLeft(self)
131                 print "current selection:", self["config"].l.getCurrentSelection()
132                 self.createSetup()
133
134         def keyRight(self):
135                 ConfigListScreen.keyRight(self)
136                 print "current selection:", self["config"].l.getCurrentSelection()
137                 self.createSetup()
138
139         def SetupPinMessageCallback(self, value):
140                 if value:
141                         self.session.openWithCallback(self.cancelCB, ParentalControlChangePin, config.ParentalControl.setuppin, _("setup PIN"))
142                 else:
143                         config.ParentalControl.setuppinactive.value = False
144                         self.keyCancel()
145
146         def ServicePinMessageCallback(self, value):
147                 if value:
148                         self.session.openWithCallback(self.cancelCB, ParentalControlChangePin, config.ParentalControl.servicepin[0], _("service PIN"))
149                 else:
150                         config.ParentalControl.servicepinactive.value = False
151                         self.keyCancel()
152
153         def cancelCB(self,value):
154                 self.keyCancel()
155
156         def keyCancel(self):
157                 if config.ParentalControl.setuppinactive.value and config.ParentalControl.setuppin.value == 'aaaa':
158                         self.session.openWithCallback(self.SetupPinMessageCallback, MessageBox, _("No valid setup PIN found!\nDo you like to change the setup PIN now?\nWhen you say 'No' here the setup protection stay disabled!"), MessageBox.TYPE_YESNO)
159                 elif config.ParentalControl.servicepinactive.value and config.ParentalControl.servicepin[0].value == 'aaaa':
160                         self.session.openWithCallback(self.ServicePinMessageCallback, MessageBox, _("No valid service PIN found!\nDo you like to change the service PIN now?\nWhen you say 'No' here the service protection stay disabled!"), MessageBox.TYPE_YESNO)
161                 else:
162                         for x in self["config"].list:
163                                 x[1].save()
164                         self.close()
165
166         def keyNumberGlobal(self, number):
167                 pass
168
169         # for summary:
170         def changedEntry(self):
171                 for x in self.onChangedEntry:
172                         x()
173
174         def getCurrentEntry(self):
175                 return self["config"].getCurrent()[0]
176
177         def getCurrentValue(self):
178                 return str(self["config"].getCurrent()[1].getText())
179
180         def createSummary(self):
181                 from Screens.Setup import SetupSummary
182                 return SetupSummary
183
184 SPECIAL_CHAR = 96
185 class ParentalControlEditor(Screen):
186         def __init__(self, session):
187                 Screen.__init__(self, session)
188                 self.list = []
189                 self.servicelist = ParentalControlList(self.list)
190                 self["servicelist"] = self.servicelist;
191                 #self.onShown.append(self.chooseLetter)
192                 self.currentLetter = chr(SPECIAL_CHAR)
193                 self.readServiceList()
194                 self.chooseLetterTimer = eTimer()
195                 self.chooseLetterTimer.callback.append(self.chooseLetter)
196                 self.onLayoutFinish.append(self.LayoutFinished)
197
198                 self["actions"] = NumberActionMap(["DirectionActions", "ColorActions", "OkCancelActions", "NumberActions"],
199                 {
200                         "ok": self.select,
201                         "cancel": self.cancel,
202                         #"left": self.keyLeft,
203                         #"right": self.keyRight,
204                         "1": self.keyNumberGlobal,
205                         "2": self.keyNumberGlobal,
206                         "3": self.keyNumberGlobal,
207                         "4": self.keyNumberGlobal,
208                         "5": self.keyNumberGlobal,
209                         "6": self.keyNumberGlobal,
210                         "7": self.keyNumberGlobal,
211                         "8": self.keyNumberGlobal,
212                         "9": self.keyNumberGlobal,
213                         "0": self.keyNumberGlobal
214                 }, -1)
215
216         def LayoutFinished(self):
217                 self.chooseLetterTimer.start(0, True)
218
219         def cancel(self):
220                 self.chooseLetter()
221
222         def select(self):
223                 self.servicelist.toggleSelectedLock()
224
225         def keyNumberGlobal(self, number):
226                 pass
227
228         def readServiceList(self):
229                 serviceHandler = eServiceCenter.getInstance()
230                 refstr = '%s ORDER BY name' % (service_types_tv)
231                 self.root = eServiceReference(refstr)
232                 self.servicesList = {}
233                 list = serviceHandler.list(self.root)
234                 if list is not None:
235                         services = list.getContent("CN", True) #(servicecomparestring, name)
236                         for s in services:
237                                 key = s[1].lower()[0]
238                                 if key < 'a' or key > 'z':
239                                         key = chr(SPECIAL_CHAR)
240                                 #key = str(key)
241                                 if not self.servicesList.has_key(key):
242                                         self.servicesList[key] = []
243                                 self.servicesList[key].append(s)
244                         
245         def chooseLetter(self):
246                 print "choose letter"
247                 mylist = []
248                 for x in self.servicesList.keys():
249                         if x == chr(SPECIAL_CHAR):
250                                 x = (_("special characters"), x)
251                         else:
252                                 x = (x, x)
253                         mylist.append(x)
254                 mylist.sort(key=itemgetter(1))
255                 sel = ord(self.currentLetter) - SPECIAL_CHAR
256                 self.session.openWithCallback(self.letterChosen, ChoiceBox, title=_("Show services beginning with"), list=mylist, keys = [], selection = sel)
257
258         def letterChosen(self, result):
259                 from Components.ParentalControl import parentalControl
260                 if result is not None:
261                         print "result:", result
262                         self.currentLetter = result[1]
263                         #Replace getProtectionLevel by new getProtectionType
264                         self.list = [ParentalControlEntryComponent(x[0], x[1], parentalControl.getProtectionType(x[0])) for x in self.servicesList[result[1]]]
265                         self.servicelist.setList(self.list)
266                 else:
267                         parentalControl.save()
268                         self.close()
269
270 class ParentalControlBouquetEditor(Screen):
271         #This new class allows adding complete bouquets to black- and whitelists
272         #The servicereference that is stored for bouquets is their refstr as listed in bouquets.tv
273         def __init__(self, session):
274                 Screen.__init__(self, session)
275                 self.skinName = "ParentalControlEditor"
276                 self.list = []
277                 self.bouquetslist = ParentalControlList(self.list)
278                 self["servicelist"] = self.bouquetslist;
279                 self.readBouquetList()
280                 self.onLayoutFinish.append(self.selectBouquet)
281
282                 self["actions"] = NumberActionMap(["DirectionActions", "ColorActions", "OkCancelActions"],
283                 {
284                         "ok": self.select,
285                         "cancel": self.cancel
286                 }, -1)
287
288         def cancel(self):
289                 from Components.ParentalControl import parentalControl
290                 parentalControl.save()
291                 self.close()
292
293         def select(self):
294                 self.bouquetslist.toggleSelectedLock()
295
296         def readBouquetList(self):
297                 serviceHandler = eServiceCenter.getInstance()
298                 refstr = '1:134:1:0:0:0:0:0:0:0:FROM BOUQUET \"bouquets.tv\" ORDER BY bouquet'
299                 bouquetroot = eServiceReference(refstr)
300                 self.bouquetlist = {}
301                 list = serviceHandler.list(bouquetroot)
302                 if list is not None:
303                         self.bouquetlist = list.getContent("CN", True)
304         
305         def selectBouquet(self):
306                 from Components.ParentalControl import parentalControl
307                 self.list = [ParentalControlEntryComponent(x[0], x[1], parentalControl.getProtectionType(x[0])) for x in self.bouquetlist]
308                 self.bouquetslist.setList(self.list)
309
310 class ParentalControlChangePin(Screen, ConfigListScreen, ProtectedScreen):
311         def __init__(self, session, pin, pinname):
312                 Screen.__init__(self, session)
313                 # for the skin: first try ParentalControlChangePin, then Setup, this allows individual skinning
314                 self.skinName = ["ParentalControlChangePin", "Setup" ]
315                 self.setup_title = _("Change pin code")
316                 self.onChangedEntry = [ ]
317
318                 self.pin = pin
319                 self.list = []
320                 self.pin1 = ConfigPIN(default = 1111, censor = "*")
321                 self.pin2 = ConfigPIN(default = 1112, censor = "*")
322                 self.pin1.addEndNotifier(boundFunction(self.valueChanged, 1))
323                 self.pin2.addEndNotifier(boundFunction(self.valueChanged, 2))
324                 self.list.append(getConfigListEntry(_("New PIN"), NoSave(self.pin1)))
325                 self.list.append(getConfigListEntry(_("Reenter new PIN"), NoSave(self.pin2)))
326                 ConfigListScreen.__init__(self, self.list)
327 #               print "old pin:", pin
328                 #if pin.value != "aaaa":
329                         #self.onFirstExecBegin.append(boundFunction(self.session.openWithCallback, self.pinEntered, PinInput, pinList = [self.pin.value], title = _("please enter the old pin"), windowTitle = _("Change pin code")))
330                 ProtectedScreen.__init__(self)
331                 
332                 self["actions"] = NumberActionMap(["DirectionActions", "ColorActions", "OkCancelActions"],
333                 {
334                         "cancel": self.cancel,
335                         "red": self.cancel,
336                         "save": self.keyOK,
337                 }, -1)
338                 self["key_red"] = StaticText(_("Cancel"))
339                 self["key_green"] = StaticText(_("OK"))
340                 self.onLayoutFinish.append(self.layoutFinished)
341
342         def layoutFinished(self):
343                 self.setTitle(self.setup_title)
344
345         def valueChanged(self, pin, value):
346                 if pin == 1:
347                         self["config"].setCurrentIndex(1)
348                 elif pin == 2:
349                         self.keyOK()
350
351         def getPinText(self):
352                 return _("Please enter the old PIN code")
353
354         def isProtected(self):
355                 return (self.pin.value != "aaaa")
356
357         def protectedWithPin(self):
358                 return self.pin.value
359
360 #       def pinEntered(self, result):
361                 #if result[0] is None:
362                         #self.close()
363                 #if not result[0]:
364                         #print result, "-", self.pin.value
365                         #self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)
366
367         def keyOK(self):
368                 if self.pin1.value == self.pin2.value:
369                         self.pin.value = self.pin1.value
370                         self.pin.save()
371                         self.session.openWithCallback(self.close, MessageBox, _("The PIN code has been changed successfully."), MessageBox.TYPE_INFO)
372                 else:
373                         self.session.open(MessageBox, _("The PIN codes you entered are different."), MessageBox.TYPE_ERROR)
374
375         def cancel(self):
376                 self.close(None)
377
378         def keyNumberGlobal(self, number):
379                 ConfigListScreen.keyNumberGlobal(self, number)
380
381         # for summary:
382         def changedEntry(self):
383                 for x in self.onChangedEntry:
384                         x()
385
386         def getCurrentEntry(self):
387                 return self["config"].getCurrent()[0]
388
389         def getCurrentValue(self):
390                 return str(self["config"].getCurrent()[1].getText())
391
392         def createSummary(self):
393                 from Screens.Setup import SetupSummary
394                 return SetupSummary