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