add missing import
[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 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 class PacketList(MenuList):
303         def __init__(self, list, enableWrapAround=True):
304                 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
305                 self.l.setFont(0, gFont("Regular", 22))
306                 self.l.setFont(1, gFont("Regular", 14))
307                 self.l.setItemHeight(52)
308
309 class PacketManager(Screen):
310         skin = """
311                 <screen position="90,80" size="530,420" title="IPKG upgrade..." >
312                         <widget name="list" position="5,10" size="520,365" zPosition="1" scrollbarMode="showOnDemand" />
313                         <widget name="status" position="30,160" size="530,40" zPosition="4" font="Regular;22" halign="left" transparent="1" />
314                         <ePixmap pixmap="skin_default/buttons/red.png" position="10,380" zPosition="2" size="140,40" transparent="1" alphatest="on" />
315                         <widget name="closetext" position="20,390" size="140,21" zPosition="10" font="Regular;21" transparent="1" />
316                         <ePixmap pixmap="skin_default/buttons/green.png" position="160,380" zPosition="2" size="140,40" transparent="1" alphatest="on" />
317                         <widget name="reloadtext" position="170,390" size="300,21" zPosition="10" font="Regular;21" transparent="1" />
318                 </screen>"""
319                 
320         def __init__(self, session, plugin_path, args = None):
321                 Screen.__init__(self, session)
322                 self.session = session
323                 self.skin_path = plugin_path
324
325                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"], 
326                 {
327                         "ok": self.go,
328                         "back": self.exit,
329                         "red": self.exit,
330                         "green": self.reload,
331                 }, -1)
332                 
333                 self.list = []
334                 self["list"] = PacketList(self.list)
335                 self.status = Label()
336                 self["closetext"] = Label(_("Close"))
337                 self["reloadtext"] = Label(_("Reload"))
338                 self["status"] = self.status                            
339
340                 self.list_updating = True
341                 self.packetlist = []
342                 self.installed_packetlist = {}
343                 self.Console = Console()
344                 self.cmdList = []
345                 self.cachelist = []
346                 self.cache_ttl = 86400  #600 is default, 0 disables, Seconds cache is considered valid (24h should be ok for caching ipkgs)
347                 self.cache_file = '/usr/lib/enigma2/python/Plugins/SystemPlugins/SoftwareManager/packetmanager.cache' #Path to cache directory   
348                 self.oktext = _("\nAfter pressing OK, please wait!")
349
350                 self.ipkg = IpkgComponent()
351                 self.ipkg.addCallback(self.ipkgCallback)
352                 self.onShown.append(self.setWindowTitle)
353                 self.onLayoutFinish.append(self.rebuildList)
354                 #self.onClose.append(self.cleanup)
355
356         def exit(self):
357                 self.ipkg.stop()
358                 if self.Console is not None:
359                         if len(self.Console.appContainers):
360                                 for name in self.Console.appContainers.keys():
361                                         self.Console.kill(name)
362                 self.close()
363
364         def cleanup(self):
365                 self.ipkg.stop()
366                 if self.Console is not None:
367                         del self.Console
368
369         def reload(self):
370                 if (os_path.exists(self.cache_file) == True):
371                         remove(self.cache_file)
372                         self.list_updating = True
373                         self.rebuildList()
374                         
375         def setWindowTitle(self):
376                 self.setTitle(_("Packet manager"))
377
378         def rebuildList(self):
379                 self["list"].instance.hide()
380                 self.status.setText(_("Package list update"))
381                 self.status.show()
382                 self.inv_cache = 0
383                 self.vc = valid_cache(self.cache_file, self.cache_ttl)
384                 if self.cache_ttl > 0 and self.vc != 0:
385                         try:
386                                 self.buildPacketList()
387                         except:
388                                 self.inv_cache = 1
389                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
390                         self.run = 0
391                         self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
392
393         def go(self, returnValue = None):
394                 cur = self['list'].l.getCurrentSelection()
395                 if cur:
396                         returnValue = cur[0]
397                         self.cmdList = []
398                         if returnValue[3] == 'installed':
399                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": returnValue[0] }))
400                                 if len(self.cmdList):
401                                         self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n" + returnValue[0] + "\n" + self.oktext))
402                         elif returnValue[3] == 'upgradeable':
403                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": returnValue[0] }))
404                                 if len(self.cmdList):
405                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to upgrade the package:\n" + returnValue[0] + "\n" + self.oktext))
406                         else:
407                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": returnValue[0] }))
408                                 if len(self.cmdList):
409                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n" + returnValue[0] + "\n" + self.oktext))
410
411         def runRemove(self, result):
412                 if result:
413                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
414
415         def runRemoveFinished(self):
416                 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
417
418         def RemoveReboot(self, result):
419                 if result is None:
420                         return
421                 if result is False:
422                         cur = self['list'].l.getCurrentSelection()
423                         if cur:
424                                 entry = cur[0]
425                                 item = self['list'].l.getCurrentSelectionIndex()
426                                 self.list[item] = self.buildEntryComponent(entry[0], entry[1], entry[2], 'installable')
427                                 self.cachelist[item] = [entry[0], entry[1], entry[2], 'installable']
428                                 self['list'].l.setList(self.list)
429                                 write_cache(self.cache_file, self.cachelist)
430                                 self.reloadPluginlist()
431                 if result:
432                         quitMainloop(3)
433
434         def runUpgrade(self, result):
435                 if result:
436                         self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
437
438         def runUpgradeFinished(self):
439                 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
440                 
441         def UpgradeReboot(self, result):
442                 if result is None:
443                         return
444                 if result is False:
445                         cur = self['list'].l.getCurrentSelection()
446                         if cur:
447                                 entry = cur[0]
448                                 item = self['list'].l.getCurrentSelectionIndex()
449                                 self.list[item] = self.buildEntryComponent(entry[0], entry[1], entry[2], 'installed')
450                                 self.cachelist[item] = [entry[0], entry[1], entry[2], 'installed']
451                                 self['list'].l.setList(self.list)
452                                 write_cache(self.cache_file, self.cachelist)
453                                 self.reloadPluginlist()
454                 if result:
455                         quitMainloop(3)
456
457         def ipkgCallback(self, event, param):
458                 if event == IpkgComponent.EVENT_ERROR:
459                         self.list_updating = False
460                         self.status.setText(_("An error occured!"))
461                 elif event == IpkgComponent.EVENT_DONE:
462                         if self.list_updating:
463                                 self.list_updating = False
464                                 if not self.Console:
465                                         self.Console = Console()
466                                 cmd = "ipkg list"
467                                 self.Console.ePopen(cmd, self.IpkgList_Finished)
468                 #print event, "-", param
469                 pass
470
471         def IpkgList_Finished(self, result, retval, extra_args = None):
472                 if len(result):
473                         self.packetlist = []
474                         for x in result.splitlines():
475                                 split = x.split(' - ')
476                                 self.packetlist.append([split[0].strip(), split[1].strip(),split[2].strip()])
477                 if not self.Console:
478                         self.Console = Console()
479                 cmd = "ipkg list_installed"
480                 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
481
482         def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
483                 if len(result):
484                         self.installed_packetlist = {}
485                         for x in result.splitlines():
486                                 split = x.split(' - ')
487                                 self.installed_packetlist[split[0].strip()] = split[1].strip()
488                 self.buildPacketList()
489
490         def PacketEntryComponent(self,entry):
491                 res = [ entry ]
492                 res.append(MultiContentEntryText(pos=(5, 1), size=(440, 28), font=0, text= entry[0]))
493                 res.append(MultiContentEntryText(pos=(5, 26), size=(440, 20), font=1, text=entry[2]))
494                 res.append(MultiContentEntryPixmapAlphaTest(pos=(445, 2), size=(48, 48), png = entry[4]))
495                 res.append(MultiContentEntryPixmapAlphaTest(pos=(5, 50), size=(510, 2), png = entry[5]))
496                 return res
497
498         def buildEntryComponent(self, name, version, description, state):
499                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
500                 if state == 'installed':
501                         installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installed.png"))
502                         return(self.PacketEntryComponent([name, version, description, state, installedpng, divpng]))
503                 elif state == 'upgradeable':
504                         upgradeablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/upgradeable.png"))
505                         return(self.PacketEntryComponent([name, version, description, state, upgradeablepng, divpng]))
506                 else:
507                         installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installable.png"))
508                         return(self.PacketEntryComponent([name, version, description, state, installablepng, divpng]))
509
510         def buildPacketList(self):
511                 self.list = []
512                 self.cachelist = []
513
514                 if self.cache_ttl > 0 and self.vc != 0:
515                         print 'Loading packagelist cache from ',self.cache_file
516                         try:
517                                 self.cachelist = load_cache(self.cache_file)
518                                 if len(self.cachelist) > 0:
519                                         for x in self.cachelist:
520                                                 self.list.append(self.buildEntryComponent(x[0], x[1], x[2], x[3]))
521                                         self['list'].l.setList(self.list)
522                                         self["list"].instance.show()
523                                         self.status.hide()
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                                 self.cachelist.append([x[0].strip(), x[1].strip(), x[2].strip(), status])       
542                         write_cache(self.cache_file, self.cachelist)
543                         self['list'].l.setList(self.list)
544                         self["list"].instance.show()
545                         self.status.hide()
546
547         def reloadPluginlist(self):
548                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
549
550 class UpdatePlugin(Screen):
551         skin = """
552                 <screen position="100,100" size="550,200" title="Software Update..." >
553                         <widget name="activityslider" position="0,0" size="550,5"  />
554                         <widget name="slider" position="0,100" size="550,30"  />
555                         <widget name="package" position="10,30" size="540,20" font="Regular;18"/>
556                         <widget name="status" position="10,60" size="540,45" font="Regular;18"/>
557                 </screen>"""
558                 
559         def __init__(self, session, args = None):
560                 self.skin = UpdatePlugin.skin
561                 Screen.__init__(self, session)
562                 
563                 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
564                 
565                 self.slider = Slider(0, 4)
566                 self["slider"] = self.slider
567                 self.activityslider = Slider(0, 100)
568                 self["activityslider"] = self.activityslider
569                 self.status = Label(_("Upgrading Dreambox... Please wait"))
570                 self["status"] = self.status
571                 self.package = Label()
572                 self["package"] = self.package
573                 
574                 self.packages = 0
575                 self.error = 0
576                 
577                 self.activity = 0
578                 self.activityTimer = eTimer()
579                 self.activityTimer.callback.append(self.doActivityTimer)
580                 self.activityTimer.start(100, False)
581                                 
582                 self.ipkg = IpkgComponent()
583                 self.ipkg.addCallback(self.ipkgCallback)
584                 
585                 self.updating = True
586                 self.package.setText(_("Package list update"))
587                 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
588                         
589                 self["actions"] = ActionMap(["WizardActions"], 
590                 {
591                         "ok": self.exit,
592                         "back": self.exit
593                 }, -1)
594                 
595         def doActivityTimer(self):
596                 self.activity += 1
597                 if self.activity == 100:
598                         self.activity = 0
599                 self.activityslider.setValue(self.activity)
600                 
601         def ipkgCallback(self, event, param):
602                 if event == IpkgComponent.EVENT_DOWNLOAD:
603                         self.status.setText(_("Downloading"))
604                 elif event == IpkgComponent.EVENT_UPGRADE:
605                         if self.sliderPackages.has_key(param):
606                                 self.slider.setValue(self.sliderPackages[param])
607                         self.package.setText(param)
608                         self.status.setText(_("Upgrading"))
609                         self.packages += 1
610                 elif event == IpkgComponent.EVENT_INSTALL:
611                         self.package.setText(param)
612                         self.status.setText(_("Installing"))
613                         self.packages += 1
614                 elif event == IpkgComponent.EVENT_CONFIGURING:
615                         self.package.setText(param)
616                         self.status.setText(_("Configuring"))
617                 elif event == IpkgComponent.EVENT_MODIFIED:
618                         self.session.openWithCallback(
619                                 self.modificationCallback,
620                                 MessageBox,
621                                 _("A configuration file (%s) was modified since Installation.\nDo you want to keep your version?") % (param)
622                         )
623                 elif event == IpkgComponent.EVENT_ERROR:
624                         self.error += 1
625                 elif event == IpkgComponent.EVENT_DONE:
626                         if self.updating:
627                                 self.updating = False
628                                 self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE, args = {'test_only': False})
629                         elif self.error == 0:
630                                 self.slider.setValue(4)
631                                 
632                                 self.activityTimer.stop()
633                                 self.activityslider.setValue(0)
634                                 
635                                 self.package.setText("")
636                                 self.status.setText(_("Done - Installed or upgraded %d packages") % self.packages)
637                         else:
638                                 self.activityTimer.stop()
639                                 self.activityslider.setValue(0)
640                                 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
641                                 if self.packages == 0:
642                                         error = _("No packages were upgraded yet. So you can check your network and try again.")
643                                 if self.updating:
644                                         error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
645                                 self.status.setText(_("Error") +  " - " + error)
646                 #print event, "-", param
647                 pass
648
649         def modificationCallback(self, res):
650                 self.ipkg.write(res and "N" or "Y")
651
652         def exit(self):
653                 if not self.ipkg.isRunning():
654                         if self.packages != 0 and self.error == 0:
655                                 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"))
656                         else:
657                                 self.close()
658                         
659         def exitAnswer(self, result):
660                 if result is not None and result:
661                         quitMainloop(2)
662                 self.close()
663
664
665
666 class IpkgInstaller(Screen):
667         skin = """
668                 <screen position="100,100" size="550,400" title="..." >
669                         <widget name="red" halign="center" valign="center" position="0,0" size="140,60" backgroundColor="red" font="Regular;21" />
670                         <widget name="green" halign="center" valign="center" position="140,0" text="Install selected" size="140,60" backgroundColor="green" font="Regular;21" />
671                         <widget name="yellow" halign="center" valign="center" position="280,0" size="140,60" backgroundColor="yellow" font="Regular;21" />
672                         <widget name="blue" halign="center" valign="center" position="420,0" size="140,60" backgroundColor="blue" font="Regular;21" />
673                         <widget name="list" position="0,60" size="550,360" />
674                 </screen>
675                 """
676         
677         def __init__(self, session, list):
678                 self.skin = IpkgInstaller.skin
679                 Screen.__init__(self, session)
680
681                 self.list = SelectionList()
682                 self["list"] = self.list
683                 for listindex in range(len(list)):
684                         self.list.addSelection(list[listindex], list[listindex], listindex, True)
685
686                 self["red"] = Label()
687                 self["green"] = Label()
688                 self["yellow"] = Label()
689                 self["blue"] = Label()
690                 
691                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], 
692                 {
693                         "ok": self.list.toggleSelection, 
694                         "cancel": self.close, 
695                         "green": self.install
696                 }, -1)
697                 
698         def install(self):
699                 list = self.list.getSelectionsList()
700                 cmdList = []
701                 for item in list:
702                         cmdList.append((IpkgComponent.CMD_INSTALL, { "package": item[1] }))
703                 self.session.open(Ipkg, cmdList = cmdList)
704
705 def filescan_open(list, session, **kwargs):
706         filelist = [x.path for x in list]
707         session.open(IpkgInstaller, filelist) # list
708
709 def filescan(**kwargs):
710         from Components.Scanner import Scanner, ScanPath
711         return \
712                 Scanner(mimetypes = ["application/x-debian-package"], 
713                         paths_to_scan = 
714                                 [
715                                         ScanPath(path = "ipk", with_subdirs = True), 
716                                         ScanPath(path = "", with_subdirs = False), 
717                                 ], 
718                         name = "Ipkg", 
719                         description = "Install software updates...", 
720                         openfnc = filescan_open, )
721
722 def UpgradeMain(session, **kwargs):
723         session.open(UpdatePluginMenu)
724
725 def startSetup(menuid):
726         if menuid != "setup": 
727                 return [ ]
728         return [(_("Software manager") + "...", UpgradeMain, "software_manager", 50)]
729
730 def Plugins(path, **kwargs):
731         global plugin_path
732         plugin_path = path
733         return [
734                 PluginDescriptor(name=_("Software manager"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_MENU, fnc=startSetup), 
735                 #PluginDescriptor(name=_("Software manager"), description=_("Manage your receiver's software"), icon="update.png", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=UpgradeMain),
736                 PluginDescriptor(name=_("Ipkg"), where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
737         ]