2bacd4140b142652a59ae97f077419ac3f4cd907
[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()
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.close,
329                         "red": self.close,
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 cleanup(self):
357                 self.ipkg.stop()
358                 if self.Console is not None:
359                         del self.Console
360
361         def reload(self):
362                 if (os_path.exists(self.cache_file) == True):
363                         remove(self.cache_file)
364                         self.list_updating = True
365                         self.rebuildList()
366                         
367         def setWindowTitle(self):
368                 self.setTitle(_("Packet manager"))
369
370         def rebuildList(self):
371                 self["list"].instance.hide()
372                 self.status.setText(_("Package list update"))
373                 self.status.show()
374                 self.inv_cache = 0
375                 self.vc = valid_cache(self.cache_file, self.cache_ttl)
376                 if self.cache_ttl > 0 and self.vc != 0:
377                         try:
378                                 self.buildPacketList()
379                         except:
380                                 self.inv_cache = 1
381                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
382                         self.run = 0
383                         self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
384
385         def go(self, returnValue = None):
386                 cur = self['list'].l.getCurrentSelection()
387                 if cur:
388                         returnValue = cur[0]
389                         self.cmdList = []
390                         if returnValue[3] == 'installed':
391                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": returnValue[0] }))
392                                 if len(self.cmdList):
393                                         self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n" + returnValue[0] + "\n" + self.oktext))
394                         elif returnValue[3] == 'upgradeable':
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 upgrade the package:\n" + returnValue[0] + "\n" + self.oktext))
398                         else:
399                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": returnValue[0] }))
400                                 if len(self.cmdList):
401                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n" + returnValue[0] + "\n" + self.oktext))
402
403         def runRemove(self, result):
404                 if result:
405                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
406
407         def runRemoveFinished(self):
408                 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
409
410         def RemoveReboot(self, result):
411                 if result is None:
412                         return
413                 if result is False:
414                         cur = self['list'].l.getCurrentSelection()
415                         if cur:
416                                 entry = cur[0]
417                                 item = self['list'].l.getCurrentSelectionIndex()
418                                 self.list[item] = PacketEntryComponent([entry[0], entry[1], entry[2], 'installable'])
419                                 self.cachelist[item] = [entry[0], entry[1], entry[2], 'installable']
420                                 self['list'].l.setList(self.list)
421                                 write_cache(self.cache_file, self.cachelist)
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 = [0]
439                                 item = self['list'].l.getCurrentSelectionIndex()
440                                 self.list[item] = PacketEntryComponent([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                 if result:
445                         quitMainloop(3)
446
447         def ipkgCallback(self, event, param):
448                 if event == IpkgComponent.EVENT_ERROR:
449                         self.list_updating = False
450                         self.status.setText(_("An error occured!"))
451                 elif event == IpkgComponent.EVENT_DONE:
452                         if self.list_updating:
453                                 self.list_updating = False
454                                 if not self.Console:
455                                         self.Console = Console()
456                                 cmd = "ipkg list"
457                                 self.Console.ePopen(cmd, self.IpkgList_Finished)
458                 #print event, "-", param
459                 pass
460
461         def IpkgList_Finished(self, result, retval, extra_args = None):
462                 if len(result):
463                         self.packetlist = []
464                         for x in result.splitlines():
465                                 split = x.split(' - ')
466                                 self.packetlist.append([split[0].strip(), split[1].strip(),split[2].strip()])
467                 if not self.Console:
468                         self.Console = Console()
469                 cmd = "ipkg list_installed"
470                 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
471
472         def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
473                 if len(result):
474                         self.installed_packetlist = {}
475                         for x in result.splitlines():
476                                 split = x.split(' - ')
477                                 self.installed_packetlist[split[0].strip()] = split[1].strip()
478                 self.buildPacketList()
479
480         def PacketEntryComponent(self,entry):
481                 res = [ entry ]
482                 res.append(MultiContentEntryText(pos=(5, 1), size=(440, 28), font=0, text= entry[0]))
483                 res.append(MultiContentEntryText(pos=(5, 26), size=(440, 20), font=1, text=entry[2]))
484                 res.append(MultiContentEntryPixmapAlphaTest(pos=(445, 2), size=(48, 48), png = entry[4]))
485                 res.append(MultiContentEntryPixmapAlphaTest(pos=(5, 50), size=(510, 2), png = entry[5]))
486                 
487                 return res
488
489
490         def buildPacketList(self):
491                 self.list = []
492                 self.cachelist = []
493                 installedpng = loadPNG(resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installed.png"))
494                 upgradeablepng = loadPNG(resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/upgradeable.png"))
495                 installablepng = loadPNG(resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/installable.png"))
496                 divpng = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
497
498                 if self.cache_ttl > 0 and self.vc != 0:
499                         print 'Loading packagelist cache from ',self.cache_file
500                         try:
501                                 self.cachelist = load_cache(self.cache_file)
502                                 if len(self.cachelist) > 0:
503                                         for x in self.cachelist:
504                                                 if x[3] == 'installed':
505                                                         self.list.append(self.PacketEntryComponent([x[0], x[1], x[2], x[3],installedpng,divpng]))
506                                                 elif x[3] == 'upgradeable':
507                                                         self.list.append(self.PacketEntryComponent([x[0], x[1], x[2], x[3],upgradeablepng,divpng]))
508                                                 else:
509                                                         self.list.append(self.PacketEntryComponent([x[0], x[1], x[2], x[3],installablepng,divpng]))
510                                         self['list'].l.setList(self.list)
511                                         self["list"].instance.show()
512                                         self.status.hide()
513                         except:
514                                 self.inv_cache = 1
515
516                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
517                         print 'rebuilding fresh package list'
518                         for x in self.packetlist:
519                                 status = ""
520                                 if self.installed_packetlist.has_key(x[0].strip()):
521                                         if self.installed_packetlist[x[0].strip()] == x[1].strip():
522                                                 status = "installed"
523                                                 self.list.append(self.PacketEntryComponent([x[0].strip(), x[1].strip(), x[2].strip(), status,installedpng,divpng]))
524                                         else:
525                                                 status = "upgradeable"
526                                                 self.list.append(self.PacketEntryComponent([x[0].strip(), x[1].strip(), x[2].strip(), status,upgradeablepng,divpng]))
527                                 else:
528                                         status = "installable"
529                                         self.list.append(self.PacketEntryComponent([x[0].strip(), x[1].strip(), x[2].strip(), status,installablepng,divpng]))
530                                 self.cachelist.append([x[0].strip(), x[1].strip(), x[2].strip(), status])       
531                         write_cache(self.cache_file, self.cachelist)
532                         self['list'].l.setList(self.list)
533                         self["list"].instance.show()
534                         self.status.hide()
535
536
537 class UpdatePlugin(Screen):
538         skin = """
539                 <screen position="100,100" size="550,200" title="Software Update..." >
540                         <widget name="activityslider" position="0,0" size="550,5"  />
541                         <widget name="slider" position="0,100" size="550,30"  />
542                         <widget name="package" position="10,30" size="540,20" font="Regular;18"/>
543                         <widget name="status" position="10,60" size="540,45" font="Regular;18"/>
544                 </screen>"""
545                 
546         def __init__(self, session, args = None):
547                 self.skin = UpdatePlugin.skin
548                 Screen.__init__(self, session)
549                 
550                 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
551                 
552                 self.slider = Slider(0, 4)
553                 self["slider"] = self.slider
554                 self.activityslider = Slider(0, 100)
555                 self["activityslider"] = self.activityslider
556                 self.status = Label(_("Upgrading Dreambox... Please wait"))
557                 self["status"] = self.status
558                 self.package = Label()
559                 self["package"] = self.package
560                 
561                 self.packages = 0
562                 self.error = 0
563                 
564                 self.activity = 0
565                 self.activityTimer = eTimer()
566                 self.activityTimer.callback.append(self.doActivityTimer)
567                 self.activityTimer.start(100, False)
568                                 
569                 self.ipkg = IpkgComponent()
570                 self.ipkg.addCallback(self.ipkgCallback)
571                 
572                 self.updating = True
573                 self.package.setText(_("Package list update"))
574                 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
575                         
576                 self["actions"] = ActionMap(["WizardActions"], 
577                 {
578                         "ok": self.exit,
579                         "back": self.exit
580                 }, -1)
581                 
582         def doActivityTimer(self):
583                 self.activity += 1
584                 if self.activity == 100:
585                         self.activity = 0
586                 self.activityslider.setValue(self.activity)
587                 
588         def ipkgCallback(self, event, param):
589                 if event == IpkgComponent.EVENT_DOWNLOAD:
590                         self.status.setText(_("Downloading"))
591                 elif event == IpkgComponent.EVENT_UPGRADE:
592                         if self.sliderPackages.has_key(param):
593                                 self.slider.setValue(self.sliderPackages[param])
594                         self.package.setText(param)
595                         self.status.setText(_("Upgrading"))
596                         self.packages += 1
597                 elif event == IpkgComponent.EVENT_INSTALL:
598                         self.package.setText(param)
599                         self.status.setText(_("Installing"))
600                         self.packages += 1
601                 elif event == IpkgComponent.EVENT_CONFIGURING:
602                         self.package.setText(param)
603                         self.status.setText(_("Configuring"))
604                 elif event == IpkgComponent.EVENT_MODIFIED:
605                         self.session.openWithCallback(
606                                 self.modificationCallback,
607                                 MessageBox,
608                                 _("A configuration file (%s) was modified since Installation.\nDo you want to keep your version?") % (param)
609                         )
610                 elif event == IpkgComponent.EVENT_ERROR:
611                         self.error += 1
612                 elif event == IpkgComponent.EVENT_DONE:
613                         if self.updating:
614                                 self.updating = False
615                                 self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE, args = {'test_only': False})
616                         elif self.error == 0:
617                                 self.slider.setValue(4)
618                                 
619                                 self.activityTimer.stop()
620                                 self.activityslider.setValue(0)
621                                 
622                                 self.package.setText("")
623                                 self.status.setText(_("Done - Installed or upgraded %d packages") % self.packages)
624                         else:
625                                 self.activityTimer.stop()
626                                 self.activityslider.setValue(0)
627                                 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
628                                 if self.packages == 0:
629                                         error = _("No packages were upgraded yet. So you can check your network and try again.")
630                                 if self.updating:
631                                         error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
632                                 self.status.setText(_("Error") +  " - " + error)
633                 #print event, "-", param
634                 pass
635
636         def modificationCallback(self, res):
637                 self.ipkg.write(res and "N" or "Y")
638
639         def exit(self):
640                 if not self.ipkg.isRunning():
641                         if self.packages != 0 and self.error == 0:
642                                 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"))
643                         else:
644                                 self.close()
645                         
646         def exitAnswer(self, result):
647                 if result is not None and result:
648                         quitMainloop(2)
649                 self.close()
650
651
652
653 class IpkgInstaller(Screen):
654         skin = """
655                 <screen position="100,100" size="550,400" title="..." >
656                         <widget name="red" halign="center" valign="center" position="0,0" size="140,60" backgroundColor="red" font="Regular;21" />
657                         <widget name="green" halign="center" valign="center" position="140,0" text="Install selected" size="140,60" backgroundColor="green" font="Regular;21" />
658                         <widget name="yellow" halign="center" valign="center" position="280,0" size="140,60" backgroundColor="yellow" font="Regular;21" />
659                         <widget name="blue" halign="center" valign="center" position="420,0" size="140,60" backgroundColor="blue" font="Regular;21" />
660                         <widget name="list" position="0,60" size="550,360" />
661                 </screen>
662                 """
663         
664         def __init__(self, session, list):
665                 self.skin = IpkgInstaller.skin
666                 Screen.__init__(self, session)
667
668                 self.list = SelectionList()
669                 self["list"] = self.list
670                 for listindex in range(len(list)):
671                         self.list.addSelection(list[listindex], list[listindex], listindex, True)
672
673                 self["red"] = Label()
674                 self["green"] = Label()
675                 self["yellow"] = Label()
676                 self["blue"] = Label()
677                 
678                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], 
679                 {
680                         "ok": self.list.toggleSelection, 
681                         "cancel": self.close, 
682                         "green": self.install
683                 }, -1)
684                 
685         def install(self):
686                 list = self.list.getSelectionsList()
687                 cmdList = []
688                 for item in list:
689                         cmdList.append((IpkgComponent.CMD_INSTALL, { "package": item[1] }))
690                 self.session.open(Ipkg, cmdList = cmdList)
691
692 def filescan_open(list, session, **kwargs):
693         filelist = [x.path for x in list]
694         session.open(IpkgInstaller, filelist) # list
695
696 def filescan(**kwargs):
697         from Components.Scanner import Scanner, ScanPath
698         return \
699                 Scanner(mimetypes = ["application/x-debian-package"], 
700                         paths_to_scan = 
701                                 [
702                                         ScanPath(path = "ipk", with_subdirs = True), 
703                                         ScanPath(path = "", with_subdirs = False), 
704                                 ], 
705                         name = "Ipkg", 
706                         description = "Install software updates...", 
707                         openfnc = filescan_open, )
708
709 def UpgradeMain(session, **kwargs):
710         session.open(UpdatePluginMenu)
711
712 def startSetup(menuid):
713         if menuid != "setup": 
714                 return [ ]
715         return [(_("Software manager") + "...", UpgradeMain, "software_manager", 50)]
716
717 def Plugins(path, **kwargs):
718         global plugin_path
719         plugin_path = path
720         return [
721                 PluginDescriptor(name=_("Software manager"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_MENU, fnc=startSetup), 
722                 #PluginDescriptor(name=_("Software manager"), description=_("Manage your receiver's software"), icon="update.png", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=UpgradeMain),
723                 PluginDescriptor(name=_("Ipkg"), where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
724         ]