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