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