Merge branch 'master' of git.opendreambox.org:/git/enigma2
[enigma2.git] / lib / python / Plugins / SystemPlugins / SoftwareUpdate / plugin.py
1 from Components.ActionMap import ActionMap, NumberActionMap
2 from Components.GUIComponent import GUIComponent
3 from Components.Input import Input
4 from Components.Ipkg import IpkgComponent
5 from Components.Label import Label
6 from Components.MenuList import MenuList
7 from Components.Slider import Slider
8 from Plugins.Plugin import PluginDescriptor
9 from Screens.Console import Console
10 from Screens.ImageWizard import ImageWizard
11 from Screens.MessageBox import MessageBox
12 from Screens.MessageBox import MessageBox
13 from Screens.Screen import Screen
14 from enigma import eTimer, quitMainloop, RT_HALIGN_LEFT, RT_VALIGN_CENTER, eListboxPythonMultiContent, eListbox, gFont
15 from os import popen
16
17
18 class UpdatePluginMenu(Screen):
19         skin = """
20                 <screen position="200,100" size="300,250" title="Update..." >
21                         <widget name="menu" position="10,10" size="290,175" scrollbarMode="showOnDemand" />
22                 </screen>"""
23                 
24         def __init__(self, session, args = 0):
25                 self.skin = UpdatePluginMenu.skin
26                 Screen.__init__(self, session)
27                 
28                 self.menu = args
29                 
30                 list = []
31                 if self.menu == 0:
32                         list.append((_("Image-Upgrade"), "image"))
33                         list.append((_("Online-Upgrade"), "upgrade"))
34                         list.append((_("Advanced"), "advanced"))
35                 elif self.menu == 1:
36                         list.append((_("Choose source"), "source"))
37                         list.append((_("Packet management"), "ipkg"))
38                         list.append((_("Settings"), "setup"))
39                 
40                 self["menu"] = MenuList(list)
41                                 
42                 self["actions"] = ActionMap(["WizardActions", "DirectionActions"], 
43                 {
44                         "ok": self.go,
45                         "back": self.close,
46                 }, -1)
47                 
48         def go(self):
49                 if self.menu == 0:
50                         if (self["menu"].l.getCurrentSelection()[1] == "image"):
51                                 self.session.open(ImageWizard)
52                         if (self["menu"].l.getCurrentSelection()[1] == "upgrade"):
53                                 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to update your Dreambox?\nAfter pressing OK, please wait!"))
54                         if (self["menu"].l.getCurrentSelection()[1] == "advanced"):
55                                 self.session.open(UpdatePluginMenu, 1)
56                 if self.menu == 1:
57                         if (self["menu"].l.getCurrentSelection()[1] == "source"):
58                                 self.session.open(IPKGSource)
59                         elif (self["menu"].l.getCurrentSelection()[1] == "ipkg"):
60                                 self.session.open(Ipkg)
61                         elif (self["menu"].l.getCurrentSelection()[1] == "setup"):
62                                 self.session.open(MessageBox, _("Function not yet implemented"), MessageBox.TYPE_ERROR)
63         
64         def runUpgrade(self, result):
65                 if result:
66                         self.session.open(Console, title = "Upgrade running...", cmdlist = ["ipkg update", "ipkg upgrade -force-defaults -force-overwrite"], finishedCallback = self.runFinished)
67
68         def runFinished(self):
69                 self.session.openWithCallback(self.reboot, MessageBox, _("Upgrade finished. Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
70                 
71         def reboot(self, result):
72                 if result is None:
73                         return
74                 if result:
75                         quitMainloop(3)
76
77 class IPKGSource(Screen):
78         skin = """
79                 <screen position="100,100" size="550,60" title="IPKG source" >
80                         <widget name="text" position="0,0" size="550,25" font="Regular;20" />
81                 </screen>"""
82                 
83         def __init__(self, session, args = None):
84                 self.skin = IPKGSource.skin
85                 Screen.__init__(self, session)
86                 
87                 fp = file('/etc/ipkg/official-feed.conf', 'r')
88                 sources = fp.readlines()
89                 fp.close()
90                 
91                 self["text"] = Input(sources[0], maxSize=False, type=Input.TEXT)
92                                 
93                 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "TextEntryActions", "KeyboardInputActions"], 
94                 {
95                         "ok": self.go,
96                         "back": self.close,
97                         "left": self.keyLeft,
98                         "right": self.keyRight,
99                         "home": self.keyHome,
100                         "end": self.keyEnd,
101                         "deleteForward": self.deleteForward,
102                         "deleteBackward": self.deleteBackward,
103                         "1": self.keyNumberGlobal,
104                         "2": self.keyNumberGlobal,
105                         "3": self.keyNumberGlobal,
106                         "4": self.keyNumberGlobal,
107                         "5": self.keyNumberGlobal,
108                         "6": self.keyNumberGlobal,
109                         "7": self.keyNumberGlobal,
110                         "8": self.keyNumberGlobal,
111                         "9": self.keyNumberGlobal,
112                         "0": self.keyNumberGlobal
113                 }, -1)
114                 
115         def go(self):
116                 fp = file('/etc/ipkg/official-feed.conf', 'w')
117                 fp.write(self["text"].getText())
118                 fp.close()
119                 self.close()
120                 
121         def keyLeft(self):
122                 self["text"].left()
123         
124         def keyRight(self):
125                 self["text"].right()
126         
127         def keyHome(self):
128                 self["text"].home()
129         
130         def keyEnd(self):
131                 self["text"].end()
132         
133         def keyDeleteForward(self):
134                 self["text"].delete()
135         
136         def keyDeleteBackward(self):
137                 self["text"].deleteBackward()
138         
139         def keyNumberGlobal(self, number):
140                 print "pressed", number
141                 self["text"].number(number)
142
143 def PacketEntryComponent(packet):
144         res = [ packet ]
145         
146         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 0,250, 30, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, packet[0]))
147         res.append((eListboxPythonMultiContent.TYPE_TEXT, 250, 0, 200, 30, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, packet[1]))
148         res.append((eListboxPythonMultiContent.TYPE_TEXT, 450, 0, 100, 30, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, packet[2]))
149         return res
150
151 class PacketList(GUIComponent):
152         def __init__(self, list):
153                 GUIComponent.__init__(self)
154                 self.l = eListboxPythonMultiContent()
155                 self.l.setList(list)
156                 self.l.setFont(0, gFont("Regular", 20))
157                 self.l.setFont(1, gFont("Regular", 18))
158         
159         def getCurrent(self):
160                 return self.l.getCurrentSelection()
161         
162         def GUIcreate(self, parent):
163                 self.instance = eListbox(parent)
164                 self.instance.setContent(self.l)
165                 self.instance.setItemHeight(30)
166         
167         def GUIdelete(self):
168                 self.instance.setContent(None)
169                 self.instance = None
170
171         def invalidate(self):
172                 self.l.invalidate()
173
174 class Ipkg2(Screen):
175         skin = """
176                 <screen position="100,100" size="550,400" title="IPKG upgrade..." >
177                         <widget name="list" position="0,0" size="550,400" scrollbarMode="showOnDemand" />
178                 </screen>"""
179                 
180         def __init__(self, session, args = None):
181                 self.skin = Ipkg.skin
182                 Screen.__init__(self, session)
183         
184                 list = []
185                 self.list = list
186                 self.fillPacketList()
187
188                 self["list"] = PacketList(self.list)
189                                 
190                 self["actions"] = ActionMap(["WizardActions"], 
191                 {
192                         "ok": self.close,
193                         "back": self.close
194                 }, -1)
195                 
196
197         def fillPacketList(self):
198                 lines = popen("ipkg list", "r").readlines()
199                 packetlist = []
200                 for x in lines:
201                         split = x.split(' - ')
202                         packetlist.append([split[0].strip(), split[1].strip()])
203                 
204                 lines = popen("ipkg list_installed", "r").readlines()
205                 
206                 installedlist = {}
207                 for x in lines:
208                         split = x.split(' - ')
209                         installedlist[split[0].strip()] = split[1].strip()
210                 
211                 for x in packetlist:
212                         status = ""
213                         if installedlist.has_key(x[0]):
214                                 if installedlist[x[0]] == x[1]:
215                                         status = "installed"
216                                 else:
217                                         status = "upgradable"
218                         self.list.append(PacketEntryComponent([x[0], x[1], status]))
219                 
220         def go(self):
221                 if self.update:
222                         self.session.openWithCallback(self.doUpdate, MessageBox, _("Do you want to update your Dreambox?\nAfter pressing OK, please wait!"))            
223                 else:
224                         self.close()
225         
226         def doUpdateDelay(self):
227                 lines = popen("ipkg update && ipkg upgrade", "r").readlines()
228                 string = ""
229                 for x in lines:
230                         string += x
231                 self["text"].setText(_("Updating finished. Here is the result:") + "\n\n" + string)
232                 self.update = False
233                         
234         
235         def doUpdate(self, val = False):
236                 if val == True:
237                         self["text"].setText(_("Updating... Please wait... This can take some minutes..."))
238                         self.delayTimer.start(0, 1)
239                 else:
240                         self.close()
241                         
242 class UpdatePlugin(Screen):
243         skin = """
244                 <screen position="100,100" size="550,200" title="Software Update..." >
245                         <widget name="activityslider" position="0,0" size="550,5"  />
246                         <widget name="slider" position="0,100" size="550,30"  />
247                         <widget name="package" position="10,30" size="540,20" font="Regular;18"/>
248                         <widget name="status" position="10,60" size="540,45" font="Regular;18"/>
249                 </screen>"""
250                 
251         def __init__(self, session, args = None):
252                 self.skin = UpdatePlugin.skin
253                 Screen.__init__(self, session)
254                 
255                 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
256                 
257                 self.slider = Slider(0, 4)
258                 self["slider"] = self.slider
259                 self.activityslider = Slider(0, 100)
260                 self["activityslider"] = self.activityslider
261                 self.status = Label(_("Upgrading Dreambox... Please wait"))
262                 self["status"] = self.status
263                 self.package = Label()
264                 self["package"] = self.package
265                 
266                 self.packages = 0
267                 self.error = 0
268                 
269                 self.activity = 0
270                 self.activityTimer = eTimer()
271                 self.activityTimer.callback.append(self.doActivityTimer)
272                 self.activityTimer.start(100, False)
273                                 
274                 self.ipkg = IpkgComponent()
275                 self.ipkg.addCallback(self.ipkgCallback)
276                 
277                 self.updating = True
278                 self.package.setText(_("Package list update"))
279                 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
280                         
281                 self["actions"] = ActionMap(["WizardActions"], 
282                 {
283                         "ok": self.exit,
284                         "back": self.exit
285                 }, -1)
286                 
287         def doActivityTimer(self):
288                 self.activity += 1
289                 if self.activity == 100:
290                         self.activity = 0
291                 self.activityslider.setValue(self.activity)
292                 
293         def ipkgCallback(self, event, param):
294                 if event == IpkgComponent.EVENT_DOWNLOAD:
295                         self.status.setText(_("Downloading"))
296                 elif event == IpkgComponent.EVENT_UPGRADE:
297                         if self.sliderPackages.has_key(param):
298                                 self.slider.setValue(self.sliderPackages[param])
299                         self.package.setText(param)
300                         self.status.setText(_("Upgrading"))
301                         self.packages += 1
302                 elif event == IpkgComponent.EVENT_INSTALL:
303                         self.package.setText(param)
304                         self.status.setText(_("Installing"))
305                         self.packages += 1
306                 elif event == IpkgComponent.EVENT_CONFIGURING:
307                         self.package.setText(param)
308                         self.status.setText(_("Configuring"))
309                 elif event == IpkgComponent.EVENT_MODIFIED:
310                         self.session.openWithCallback(
311                                 self.modificationCallback,
312                                 MessageBox,
313                                 _("A configuration file (%s) was modified since Installation.\nDo you want to keep your version?") % (param)
314                         )
315                 elif event == IpkgComponent.EVENT_ERROR:
316                         self.error += 1
317                 elif event == IpkgComponent.EVENT_DONE:
318                         if self.updating:
319                                 self.updating = False
320                                 self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE, args = {'test_only': False})
321                         elif self.error == 0:
322                                 self.slider.setValue(4)
323                                 
324                                 self.activityTimer.stop()
325                                 self.activityslider.setValue(0)
326                                 
327                                 self.package.setText("")
328                                 self.status.setText(_("Done - Installed or upgraded %d packages") % self.packages)
329                         else:
330                                 self.activityTimer.stop()
331                                 self.activityslider.setValue(0)
332                                 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
333                                 if self.packages == 0:
334                                         error = _("No packages were upgraded yet. So you can check your network and try again.")
335                                 if self.updating:
336                                         error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
337                                 self.status.setText(_("Error") +  " - " + error)
338                 #print event, "-", param
339                 pass
340
341         def modificationCallback(self, res):
342                 self.ipkg.write(res and "N" or "Y")
343
344         def exit(self):
345                 if not self.ipkg.isRunning():
346                         if self.packages != 0 and self.error == 0:
347                                 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished. Do you want to reboot your Dreambox?"))
348                         else:
349                                 self.close()
350                         
351         def exitAnswer(self, result):
352                 if result is not None and result:
353                         quitMainloop(2)
354                 self.close()
355
356 def UpgradeMain(session, **kwargs):
357         session.open(UpdatePlugin)
358
359 def Plugins(**kwargs):
360         return PluginDescriptor(name="Softwareupdate", description=_("Updates your receiver's software"), icon="update.png", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=UpgradeMain)