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