fix possible crash (seen in crashlog)
[enigma2.git] / lib / python / Plugins / SystemPlugins / SoftwareManager / plugin.py
1 from Plugins.Plugin import PluginDescriptor
2 from Screens.Console import Console
3 from Screens.ChoiceBox import ChoiceBox
4 from Screens.MessageBox import MessageBox
5 from Screens.Screen import Screen
6 from Screens.Ipkg import Ipkg
7 from Components.ActionMap import ActionMap, NumberActionMap
8 from Components.Input import Input
9 from Components.Ipkg import IpkgComponent
10 from Components.Label import Label
11 from Components.MenuList import MenuList
12 from Components.Sources.List import List
13 from Components.Slider import Slider
14 from Components.Harddisk import harddiskmanager
15 from Components.config import config,getConfigListEntry, ConfigSubsection, ConfigText, ConfigLocations
16 from Components.Console import Console
17 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
18 from Components.SelectionList import SelectionList
19 from Tools.Directories import fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE
20 from Tools.LoadPixmap import LoadPixmap
21 from enigma import eTimer,  loadPNG, quitMainloop, RT_HALIGN_LEFT, RT_VALIGN_CENTER, eListboxPythonMultiContent, eListbox, gFont
22 from cPickle import dump, load
23
24 from os import path as os_path, system as os_system, unlink, stat, mkdir, popen, makedirs, listdir, access, rename, remove, W_OK, R_OK, F_OK
25 from time import time, gmtime, strftime, localtime
26 from stat import ST_MTIME
27 from datetime import date
28
29 from ImageWizard import ImageWizard
30 from BackupRestore import BackupSelection, RestoreMenu, BackupScreen, RestoreScreen, getBackupPath, getBackupFilename
31
32 config.plugins.configurationbackup = ConfigSubsection()
33 config.plugins.configurationbackup.backuplocation = ConfigText(default = '/media/hdd/', visible_width = 50, fixed_size = False)
34 config.plugins.configurationbackup.backupdirs = ConfigLocations(default=['/etc/enigma2/', '/etc/network/interfaces', '/etc/wpa_supplicant.conf'])
35
36
37 def write_cache(cache_file, cache_data):
38         #Does a cPickle dump
39         if not os_path.isdir( os_path.dirname(cache_file) ):
40                 try:
41                         mkdir( os_path.dirname(cache_file) )
42                 except OSError:
43                             print os_path.dirname(cache_file), 'is a file'
44         fd = open(cache_file, 'w')
45         dump(cache_data, fd, -1)
46         fd.close()
47
48 def valid_cache(cache_file, cache_ttl):
49         #See if the cache file exists and is still living
50         try:
51                 mtime = stat(cache_file)[ST_MTIME]
52         except:
53                 return 0
54         curr_time = time()
55         if (curr_time - mtime) > cache_ttl:
56                 return 0
57         else:
58                 return 1
59
60 def load_cache(cache_file):
61         #Does a cPickle load
62         fd = open(cache_file)
63         cache_data = load(fd)
64         fd.close()
65         return cache_data
66
67
68 class UpdatePluginMenu(Screen):
69         skin = """
70                 <screen name="UpdatePluginMenu" position="90,130" size="550,330" title="Softwaremanager..." >
71                         <ePixmap pixmap="skin_default/border_menu.png" position="10,10" zPosition="1" size="250,300" transparent="1" alphatest="on" />
72                         <widget source="menu" render="Listbox" position="20,20" size="230,260" scrollbarMode="showOnDemand">
73                                 <convert type="TemplatedMultiContent">
74                                         {"template": [
75                                                         MultiContentEntryText(pos = (2, 2), size = (230, 22), flags = RT_HALIGN_LEFT, text = 1), # index 0 is the MenuText,
76                                                 ],
77                                         "fonts": [gFont("Regular", 20)],
78                                         "itemHeight": 25
79                                         }
80                                 </convert>
81                         </widget>
82                         <widget source="menu" render="Listbox" position="280,10" size="230,300" scrollbarMode="showNever" selectionDisabled="1">
83                                 <convert type="TemplatedMultiContent">
84                                         {"template": [
85                                                         MultiContentEntryText(pos = (2, 2), size = (230, 300), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, text = 2), # index 0 is the MenuText,
86                                                 ],
87                                         "fonts": [gFont("Regular", 20)],
88                                         "itemHeight": 230
89                                         }
90                                 </convert>
91                         </widget>
92                 </screen>"""
93                 
94         def __init__(self, session, args = 0):
95                 Screen.__init__(self, session)
96                 self.skin_path = plugin_path
97                 self.menu = args
98                 self.list = []
99                 self.oktext = _("\nPress OK on your remote control to continue.")
100                 self.backupdirs = ' '.join( config.plugins.configurationbackup.backupdirs.value )
101                 if self.menu == 0:
102                         self.list.append(("software-update", _("Software update"), _("\nOnline update of your Dreambox software." ) + self.oktext) )
103                         self.list.append(("software-restore", _("Software restore"), _("\nRestore your Dreambox with a new firmware." ) + self.oktext))
104                         self.list.append(("system-backup", _("Backup system settings"), _("\nBackup your Dreambox settings." ) + self.oktext))
105                         self.list.append(("system-restore",_("Restore system settings"), _("\nRestore your Dreambox settings." ) + self.oktext))
106                         if config.usage.setup_level.index >= 2: # expert+
107                                 self.list.append(("advanced", _("Advanced Options"), _("\nAdvanced options and settings." ) + self.oktext))
108                 elif self.menu == 1:
109                         self.list.append(("ipkg-manager", _("Packet management"),  _("\nView, install and remove available or installed packages." ) + self.oktext))
110                         self.list.append(("ipkg-install", _("Install local IPKG"),  _("\nScan for local packages and install them." ) + self.oktext))
111                         self.list.append(("advancedrestore", _("Advanced restore"), _("\nRestore your backups by date." ) + self.oktext))
112                         self.list.append(("backuplocation", _("Choose backup location"),  _("\nSelect your backup device.\nCurrent device: " ) + config.plugins.configurationbackup.backuplocation.value + self.oktext ))
113                         self.list.append(("backupfiles", _("Choose backup files"),  _("Select files for backup. Currently selected:\n" ) + self.backupdirs + self.oktext))
114                         self.list.append(("ipkg-source",_("Choose upgrade source"), _("\nEdit the upgrade source address." ) + self.oktext))
115
116                 self["menu"] = List(self.list)
117                                 
118                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
119                 {
120                         "ok": self.go,
121                         "back": self.close,
122                         "red": self.close,
123                 }, -1)
124
125                 self.onLayoutFinish.append(self.layoutFinished)
126                 self.backuppath = getBackupPath()
127                 self.backupfile = getBackupFilename()
128                 self.fullbackupfilename = self.backuppath + "/" + self.backupfile
129                 self.onShown.append(self.setWindowTitle)
130                 
131         def layoutFinished(self):
132                 idx = 0
133                 self["menu"].index = idx
134                 
135         def setWindowTitle(self):
136                 self.setTitle(_("Software manager..."))
137                 
138         def go(self):
139                 current = self["menu"].getCurrent()[0]
140                 if self.menu == 0:
141                         if (current == "software-restore"):
142                                 self.session.open(ImageWizard)
143                         elif (current == "software-update"):
144                                 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to update your Dreambox?")+"\n"+_("\nAfter pressing OK, please wait!"))
145                         elif (current == "advanced"):
146                                 self.session.open(UpdatePluginMenu, 1)
147                         elif (current == "system-backup"):
148                                 self.session.openWithCallback(self.backupDone,BackupScreen, runBackup = True)
149                         elif (current == "system-restore"):
150                                 if os_path.exists(self.fullbackupfilename):
151                                         self.session.openWithCallback(self.startRestore, MessageBox, _("Are you sure you want to restore your Enigma2 backup?\nEnigma2 will restart after the restore"))
152                                 else:   
153                                         self.session.open(MessageBox, _("Sorry no backups found!"), MessageBox.TYPE_INFO)
154                 if self.menu == 1:
155                         if (current == "ipkg-manager"):
156                                 self.session.open(PacketManager, self.skin_path)
157                         elif (current == "ipkg-source"):
158                                 self.session.open(IPKGSource)
159                         elif (current == "ipkg-install"):
160                                 try:
161                                         from Plugins.Extensions.MediaScanner.plugin import main
162                                         main(self.session)
163                                 except:
164                                         self.session.open(MessageBox, _("Sorry MediaScanner is not installed!"), MessageBox.TYPE_INFO)
165                         elif (current == "backuplocation"):
166                                 parts = [ (r.description, r.mountpoint, self.session) for r in harddiskmanager.getMountedPartitions(onlyhotplug = False)]
167                                 for x in parts:
168                                         if not access(x[1], F_OK|R_OK|W_OK) or x[1] == '/':
169                                                 parts.remove(x)
170                                 for x in parts:
171                                         if x[1].startswith('/autofs/'):
172                                                 parts.remove(x)                                 
173                                 if len(parts):
174                                         self.session.openWithCallback(self.backuplocation_choosen, ChoiceBox, title = _("Please select medium to use as backup location"), list = parts)
175                         elif (current == "backupfiles"):
176                                 self.session.openWithCallback(self.backupfiles_choosen,BackupSelection)
177                         elif (current == "advancedrestore"):
178                                 self.session.open(RestoreMenu, self.skin_path)                  
179
180         def backupfiles_choosen(self, ret):
181                 self.backupdirs = ' '.join( config.plugins.configurationbackup.backupdirs.value )
182
183         def backuplocation_choosen(self, option):
184                 if option is not None:
185                         config.plugins.configurationbackup.backuplocation.value = str(option[1])
186                 config.plugins.configurationbackup.backuplocation.save()
187                 config.plugins.configurationbackup.save()
188                 config.save()
189                 self.createBackupfolders()
190         
191         def runUpgrade(self, result):
192                 if result:
193                         self.session.open(UpdatePlugin, self.skin_path)
194
195         """def runFinished(self):
196                 self.session.openWithCallback(self.reboot, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
197                 
198         def reboot(self, result):
199                 if result is None:
200                         return
201                 if result:
202                         quitMainloop(3)"""
203
204         def createBackupfolders(self):
205                 print "Creating backup folder if not already there..."
206                 self.backuppath = getBackupPath()
207                 try:
208                         if (os_path.exists(self.backuppath) == False):
209                                 makedirs(self.backuppath)
210                 except OSError:
211                         self.session.open(MessageBox, _("Sorry, your backup destination is not writeable.\n\nPlease choose another one."), MessageBox.TYPE_INFO)
212
213         def backupDone(self,retval = None):
214                 if retval is True:
215                         self.session.open(MessageBox, _("Backup done."), MessageBox.TYPE_INFO)
216                 else:
217                         self.session.open(MessageBox, _("Backup failed."), MessageBox.TYPE_INFO)
218
219         def startRestore(self, ret = False):
220                 if (ret == True):
221                         self.exe = True
222                         self.session.open(RestoreScreen, runRestore = True)
223
224
225 class IPKGSource(Screen):
226         skin = """
227                 <screen position="100,100" size="550,60" title="IPKG source" >
228                         <widget name="text" position="0,0" size="550,25" font="Regular;20" backgroundColor="background" foregroundColor="#cccccc" />
229                 </screen>"""
230                 
231         def __init__(self, session, args = None):
232                 Screen.__init__(self, session)
233                 self.session = session
234                 
235                 fp = file('/etc/ipkg/official-feed.conf', 'r')
236                 sources = fp.readlines()
237                 fp.close()
238                 
239                 self["text"] = Input(sources[0], maxSize=False, type=Input.TEXT)
240                                 
241                 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "TextEntryActions", "KeyboardInputActions"], 
242                 {
243                         "ok": self.go,
244                         "back": self.close,
245                         "left": self.keyLeft,
246                         "right": self.keyRight,
247                         "home": self.keyHome,
248                         "end": self.keyEnd,
249                         "deleteForward": self.keyDeleteForward,
250                         "deleteBackward": self.keyDeleteBackward,
251                         "1": self.keyNumberGlobal,
252                         "2": self.keyNumberGlobal,
253                         "3": self.keyNumberGlobal,
254                         "4": self.keyNumberGlobal,
255                         "5": self.keyNumberGlobal,
256                         "6": self.keyNumberGlobal,
257                         "7": self.keyNumberGlobal,
258                         "8": self.keyNumberGlobal,
259                         "9": self.keyNumberGlobal,
260                         "0": self.keyNumberGlobal
261                 }, -1)
262                 
263         def go(self):
264                 fp = file('/etc/ipkg/official-feed.conf', 'w')
265                 fp.write(self["text"].getText())
266                 fp.close()
267                 self.close()
268                 
269         def keyLeft(self):
270                 self["text"].left()
271         
272         def keyRight(self):
273                 self["text"].right()
274         
275         def keyHome(self):
276                 self["text"].home()
277         
278         def keyEnd(self):
279                 self["text"].end()
280         
281         def keyDeleteForward(self):
282                 self["text"].delete()
283         
284         def keyDeleteBackward(self):
285                 self["text"].deleteBackward()
286         
287         def keyNumberGlobal(self, number):
288                 print "pressed", number
289                 self["text"].number(number)
290
291
292 class PacketList(MenuList):
293         def __init__(self, list, enableWrapAround=True):
294                 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
295                 self.l.setFont(0, gFont("Regular", 22))
296                 self.l.setFont(1, gFont("Regular", 14))
297                 self.l.setItemHeight(52)
298
299 class PacketManager(Screen):
300         skin = """
301                 <screen position="90,80" size="530,420" title="IPKG upgrade..." >
302                         <widget name="list" position="5,10" size="520,365" zPosition="1" scrollbarMode="showOnDemand" />
303                         <widget name="status" position="30,160" size="530,40" zPosition="4" font="Regular;22" halign="left" transparent="1" />
304                         <ePixmap pixmap="skin_default/buttons/red.png" position="10,380" zPosition="2" size="140,40" transparent="1" alphatest="on" />
305                         <widget name="closetext" position="20,390" size="140,21" zPosition="10" font="Regular;21" transparent="1" />
306                         <ePixmap pixmap="skin_default/buttons/green.png" position="160,380" zPosition="2" size="140,40" transparent="1" alphatest="on" />
307                         <widget name="reloadtext" position="170,390" size="300,21" zPosition="10" font="Regular;21" transparent="1" />
308                 </screen>"""
309                 
310         def __init__(self, session, plugin_path, args = None):
311                 Screen.__init__(self, session)
312                 self.session = session
313                 self.skin_path = plugin_path
314
315                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"], 
316                 {
317                         "ok": self.go,
318                         "back": self.close,
319                         "red": self.close,
320                         "green": self.reload,
321                 }, -1)
322                 
323                 self.list = []
324                 self["list"] = PacketList(self.list)
325                 self.status = Label()
326                 self["closetext"] = Label(_("Close"))
327                 self["reloadtext"] = Label(_("Reload"))
328                 self["status"] = self.status                            
329
330                 self.list_updating = True
331                 self.packetlist = []
332                 self.installed_packetlist = {}
333                 self.Console = Console()
334                 self.cmdList = []
335                 self.cachelist = []
336                 self.cache_ttl = 86400  #600 is default, 0 disables, Seconds cache is considered valid (24h should be ok for caching ipkgs)
337                 self.cache_file = '/usr/lib/enigma2/python/Plugins/SystemPlugins/SoftwareManager/packetmanager.cache' #Path to cache directory   
338                 self.oktext = _("\nAfter pressing OK, please wait!")
339
340                 self.ipkg = IpkgComponent()
341                 self.ipkg.addCallback(self.ipkgCallback)
342                 self.onShown.append(self.setWindowTitle)
343                 self.onLayoutFinish.append(self.rebuildList)
344                 self.onClose.append(self.cleanup)
345
346         def cleanup(self):
347                 self.ipkg.stop()
348                 if self.Console is not None:
349                         del self.Console
350
351         def reload(self):
352                 if (os_path.exists(self.cache_file) == True):
353                         remove(self.cache_file)
354                         self.list_updating = True
355                         self.rebuildList()
356                         
357         def setWindowTitle(self):
358                 self.setTitle(_("Packet manager"))
359
360         def rebuildList(self):
361                 self["list"].instance.hide()
362                 self.status.setText(_("Package list update"))
363                 self.status.show()
364                 self.inv_cache = 0
365                 self.vc = valid_cache(self.cache_file, self.cache_ttl)
366                 if self.cache_ttl > 0 and self.vc != 0:
367                         try:
368                                 self.buildPacketList()
369                         except:
370                                 self.inv_cache = 1
371                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
372                         self.run = 0
373                         self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
374
375         def go(self, returnValue = None):
376                 returnValue = self['list'].l.getCurrentSelection()[0]
377                 self.cmdList = []
378                 if returnValue[3] == 'installed':
379                         self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": returnValue[0] }))
380                         if len(self.cmdList):
381                                 self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n" + returnValue[0] + "\n" + self.oktext))
382                 elif returnValue[3] == 'upgradeable':
383                         self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": returnValue[0] }))
384                         if len(self.cmdList):
385                                 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to upgrade the package:\n" + returnValue[0] + "\n" + self.oktext))
386                 else:
387                         self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": returnValue[0] }))
388                         if len(self.cmdList):
389                                 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n" + returnValue[0] + "\n" + self.oktext))
390
391         def runRemove(self, result):
392                 if result:
393                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
394
395         def runRemoveFinished(self):
396                 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
397
398         def RemoveReboot(self, result):
399                 if result is None:
400                         return
401                 if result is False:
402                         entry = self['list'].l.getCurrentSelection()[0]
403                         item = self['list'].l.getCurrentSelectionIndex()
404                         self.list[item] = PacketEntryComponent([entry[0], entry[1], entry[2], 'installable'])
405                         self.cachelist[item] = [entry[0], entry[1], entry[2], 'installable']
406                         self['list'].l.setList(self.list)
407                         write_cache(self.cache_file, self.cachelist)
408                 if result:
409                         quitMainloop(3)
410
411         def runUpgrade(self, result):
412                 if result:
413                         self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
414
415         def runUpgradeFinished(self):
416                 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
417                 
418         def UpgradeReboot(self, result):
419                 if result is None:
420                         return
421                 if result is False:
422                         entry = self['list'].l.getCurrentSelection()[0]
423                         item = self['list'].l.getCurrentSelectionIndex()
424                         self.list[item] = PacketEntryComponent([entry[0], entry[1], entry[2], 'installed'])
425                         self.cachelist[item] = [entry[0], entry[1], entry[2], 'installed']
426                         self['list'].l.setList(self.list)
427                         write_cache(self.cache_file, self.cachelist)
428                 if result:
429                         quitMainloop(3)
430
431         def ipkgCallback(self, event, param):
432                 if event == IpkgComponent.EVENT_ERROR:
433                         self.list_updating = False
434                         self.status.setText(_("An error occured!"))
435                 elif event == IpkgComponent.EVENT_DONE:
436                         if self.list_updating:
437                                 self.list_updating = False
438                                 if not self.Console:
439                                         self.Console = Console()
440                                 cmd = "ipkg list"
441                                 self.Console.ePopen(cmd, self.IpkgList_Finished)
442                 #print event, "-", param
443                 pass
444
445         def IpkgList_Finished(self, result, retval, extra_args = None):
446                 if len(result):
447                         self.packetlist = []
448                         for x in result.splitlines():
449                                 split = x.split(' - ')
450                                 self.packetlist.append([split[0].strip(), split[1].strip(),split[2].strip()])
451                 if not self.Console:
452                         self.Console = Console()
453                 cmd = "ipkg list_installed"
454                 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
455
456         def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
457                 if len(result):
458                         self.installed_packetlist = {}
459                         for x in result.splitlines():
460                                 split = x.split(' - ')
461                                 self.installed_packetlist[split[0].strip()] = split[1].strip()
462                 self.buildPacketList()
463
464         def PacketEntryComponent(self,entry):
465                 res = [ entry ]
466                 res.append(MultiContentEntryText(pos=(5, 1), size=(440, 28), font=0, text= entry[0]))
467                 res.append(MultiContentEntryText(pos=(5, 26), size=(440, 20), font=1, text=entry[2]))
468                 res.append(MultiContentEntryPixmapAlphaTest(pos=(445, 2), size=(48, 48), png = entry[4]))
469                 res.append(MultiContentEntryPixmapAlphaTest(pos=(5, 50), size=(510, 2), png = entry[5]))
470                 
471                 return res
472
473
474         def buildPacketList(self):
475                 self.list = []
476                 self.cachelist = []
477                 installedpng = loadPNG(resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installed.png"))
478                 upgradeablepng = loadPNG(resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/upgradeable.png"))
479                 installablepng = loadPNG(resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installable.png"))
480                 divpng = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
481
482                 if self.cache_ttl > 0 and self.vc != 0:
483                         print 'Loading packagelist cache from ',self.cache_file
484                         try:
485                                 self.cachelist = load_cache(self.cache_file)
486                                 if len(self.cachelist) > 0:
487                                         for x in self.cachelist:
488                                                 if x[3] == 'installed':
489                                                         self.list.append(self.PacketEntryComponent([x[0], x[1], x[2], x[3],installedpng,divpng]))
490                                                 elif x[3] == 'upgradeable':
491                                                         self.list.append(self.PacketEntryComponent([x[0], x[1], x[2], x[3],upgradeablepng,divpng]))
492                                                 else:
493                                                         self.list.append(self.PacketEntryComponent([x[0], x[1], x[2], x[3],installablepng,divpng]))
494                                         self['list'].l.setList(self.list)
495                                         self["list"].instance.show()
496                                         self.status.hide()
497                         except:
498                                 self.inv_cache = 1
499
500                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
501                         print 'rebuilding fresh package list'
502                         for x in self.packetlist:
503                                 status = ""
504                                 if self.installed_packetlist.has_key(x[0].strip()):
505                                         if self.installed_packetlist[x[0].strip()] == x[1].strip():
506                                                 status = "installed"
507                                                 self.list.append(self.PacketEntryComponent([x[0].strip(), x[1].strip(), x[2].strip(), status,installedpng,divpng]))
508                                         else:
509                                                 status = "upgradeable"
510                                                 self.list.append(self.PacketEntryComponent([x[0].strip(), x[1].strip(), x[2].strip(), status,upgradeablepng,divpng]))
511                                 else:
512                                         status = "installable"
513                                         self.list.append(self.PacketEntryComponent([x[0].strip(), x[1].strip(), x[2].strip(), status,installablepng,divpng]))
514                                 self.cachelist.append([x[0].strip(), x[1].strip(), x[2].strip(), status])       
515                         write_cache(self.cache_file, self.cachelist)
516                         self['list'].l.setList(self.list)
517                         self["list"].instance.show()
518                         self.status.hide()
519
520
521 class UpdatePlugin(Screen):
522         skin = """
523                 <screen position="100,100" size="550,200" title="Software Update..." >
524                         <widget name="activityslider" position="0,0" size="550,5"  />
525                         <widget name="slider" position="0,100" size="550,30"  />
526                         <widget name="package" position="10,30" size="540,20" font="Regular;18"/>
527                         <widget name="status" position="10,60" size="540,45" font="Regular;18"/>
528                 </screen>"""
529                 
530         def __init__(self, session, args = None):
531                 self.skin = UpdatePlugin.skin
532                 Screen.__init__(self, session)
533                 
534                 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
535                 
536                 self.slider = Slider(0, 4)
537                 self["slider"] = self.slider
538                 self.activityslider = Slider(0, 100)
539                 self["activityslider"] = self.activityslider
540                 self.status = Label(_("Upgrading Dreambox... Please wait"))
541                 self["status"] = self.status
542                 self.package = Label()
543                 self["package"] = self.package
544                 
545                 self.packages = 0
546                 self.error = 0
547                 
548                 self.activity = 0
549                 self.activityTimer = eTimer()
550                 self.activityTimer.callback.append(self.doActivityTimer)
551                 self.activityTimer.start(100, False)
552                                 
553                 self.ipkg = IpkgComponent()
554                 self.ipkg.addCallback(self.ipkgCallback)
555                 
556                 self.updating = True
557                 self.package.setText(_("Package list update"))
558                 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
559                         
560                 self["actions"] = ActionMap(["WizardActions"], 
561                 {
562                         "ok": self.exit,
563                         "back": self.exit
564                 }, -1)
565                 
566         def doActivityTimer(self):
567                 self.activity += 1
568                 if self.activity == 100:
569                         self.activity = 0
570                 self.activityslider.setValue(self.activity)
571                 
572         def ipkgCallback(self, event, param):
573                 if event == IpkgComponent.EVENT_DOWNLOAD:
574                         self.status.setText(_("Downloading"))
575                 elif event == IpkgComponent.EVENT_UPGRADE:
576                         if self.sliderPackages.has_key(param):
577                                 self.slider.setValue(self.sliderPackages[param])
578                         self.package.setText(param)
579                         self.status.setText(_("Upgrading"))
580                         self.packages += 1
581                 elif event == IpkgComponent.EVENT_INSTALL:
582                         self.package.setText(param)
583                         self.status.setText(_("Installing"))
584                         self.packages += 1
585                 elif event == IpkgComponent.EVENT_CONFIGURING:
586                         self.package.setText(param)
587                         self.status.setText(_("Configuring"))
588                 elif event == IpkgComponent.EVENT_MODIFIED:
589                         self.session.openWithCallback(
590                                 self.modificationCallback,
591                                 MessageBox,
592                                 _("A configuration file (%s) was modified since Installation.\nDo you want to keep your version?") % (param)
593                         )
594                 elif event == IpkgComponent.EVENT_ERROR:
595                         self.error += 1
596                 elif event == IpkgComponent.EVENT_DONE:
597                         if self.updating:
598                                 self.updating = False
599                                 self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE, args = {'test_only': False})
600                         elif self.error == 0:
601                                 self.slider.setValue(4)
602                                 
603                                 self.activityTimer.stop()
604                                 self.activityslider.setValue(0)
605                                 
606                                 self.package.setText("")
607                                 self.status.setText(_("Done - Installed or upgraded %d packages") % self.packages)
608                         else:
609                                 self.activityTimer.stop()
610                                 self.activityslider.setValue(0)
611                                 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
612                                 if self.packages == 0:
613                                         error = _("No packages were upgraded yet. So you can check your network and try again.")
614                                 if self.updating:
615                                         error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
616                                 self.status.setText(_("Error") +  " - " + error)
617                 #print event, "-", param
618                 pass
619
620         def modificationCallback(self, res):
621                 self.ipkg.write(res and "N" or "Y")
622
623         def exit(self):
624                 if not self.ipkg.isRunning():
625                         if self.packages != 0 and self.error == 0:
626                                 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"))
627                         else:
628                                 self.close()
629                         
630         def exitAnswer(self, result):
631                 if result is not None and result:
632                         quitMainloop(2)
633                 self.close()
634
635
636
637 class IpkgInstaller(Screen):
638         skin = """
639                 <screen position="100,100" size="550,400" title="..." >
640                         <widget name="red" halign="center" valign="center" position="0,0" size="140,60" backgroundColor="red" font="Regular;21" />
641                         <widget name="green" halign="center" valign="center" position="140,0" text="Install selected" size="140,60" backgroundColor="green" font="Regular;21" />
642                         <widget name="yellow" halign="center" valign="center" position="280,0" size="140,60" backgroundColor="yellow" font="Regular;21" />
643                         <widget name="blue" halign="center" valign="center" position="420,0" size="140,60" backgroundColor="blue" font="Regular;21" />
644                         <widget name="list" position="0,60" size="550,360" />
645                 </screen>
646                 """
647         
648         def __init__(self, session, list):
649                 self.skin = IpkgInstaller.skin
650                 Screen.__init__(self, session)
651
652                 self.list = SelectionList()
653                 self["list"] = self.list
654                 for listindex in range(len(list)):
655                         self.list.addSelection(list[listindex], list[listindex], listindex, True)
656
657                 self["red"] = Label()
658                 self["green"] = Label()
659                 self["yellow"] = Label()
660                 self["blue"] = Label()
661                 
662                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], 
663                 {
664                         "ok": self.list.toggleSelection, 
665                         "cancel": self.close, 
666                         "green": self.install
667                 }, -1)
668                 
669         def install(self):
670                 list = self.list.getSelectionsList()
671                 cmdList = []
672                 for item in list:
673                         cmdList.append((IpkgComponent.CMD_INSTALL, { "package": item[1] }))
674                 self.session.open(Ipkg, cmdList = cmdList)
675
676 def filescan_open(list, session, **kwargs):
677         filelist = [x.path for x in list]
678         session.open(IpkgInstaller, filelist) # list
679
680 def filescan(**kwargs):
681         from Components.Scanner import Scanner, ScanPath
682         return \
683                 Scanner(mimetypes = ["application/x-debian-package"], 
684                         paths_to_scan = 
685                                 [
686                                         ScanPath(path = "ipk", with_subdirs = True), 
687                                         ScanPath(path = "", with_subdirs = False), 
688                                 ], 
689                         name = "Ipkg", 
690                         description = "Install software updates...", 
691                         openfnc = filescan_open, )
692
693 def UpgradeMain(session, **kwargs):
694         session.open(UpdatePluginMenu)
695
696 def startSetup(menuid):
697         if menuid != "setup": 
698                 return [ ]
699         return [(_("Software manager") + "...", UpgradeMain, "software_manager", 50)]
700
701 def Plugins(path, **kwargs):
702         global plugin_path
703         plugin_path = path
704         return [
705                 PluginDescriptor(name=_("Software manager"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_MENU, fnc=startSetup), 
706                 #PluginDescriptor(name=_("Software manager"), description=_("Manage your receiver's software"), icon="update.png", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=UpgradeMain),
707                 PluginDescriptor(name=_("Ipkg"), where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
708         ]