SoftwareManager/plugin.py: - small cleanup and fix. This is for #112
[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.Sources.StaticText import StaticText
11 from Components.ScrollLabel import ScrollLabel
12 from Components.Pixmap import Pixmap
13 from Components.MenuList import MenuList
14 from Components.Sources.List import List
15 from Components.Slider import Slider
16 from Components.Harddisk import harddiskmanager
17 from Components.config import config,getConfigListEntry, ConfigSubsection, ConfigText, ConfigLocations
18 from Components.Console import Console
19 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
20 from Components.SelectionList import SelectionList
21 from Components.PluginComponent import plugins
22 from Components.About import about
23 from Components.DreamInfoHandler import DreamInfoHandler
24 from Components.Language import language
25 from Components.AVSwitch import AVSwitch
26 from Components.Network import iNetwork
27 from Tools.Directories import pathExists, fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_CURRENT_PLUGIN, SCOPE_CURRENT_SKIN, SCOPE_METADIR
28 from Tools.LoadPixmap import LoadPixmap
29 from enigma import eTimer, quitMainloop, RT_HALIGN_LEFT, RT_VALIGN_CENTER, eListboxPythonMultiContent, eListbox, gFont, getDesktop, ePicLoad
30 from cPickle import dump, load
31 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
32 from time import time, gmtime, strftime, localtime
33 from stat import ST_MTIME
34 from datetime import date
35 from twisted.web import client
36 from twisted.internet import reactor
37
38 from ImageWizard import ImageWizard
39 from BackupRestore import BackupSelection, RestoreMenu, BackupScreen, RestoreScreen, getBackupPath, getBackupFilename
40 from SoftwareTools import iSoftwareTools
41
42 config.plugins.configurationbackup = ConfigSubsection()
43 config.plugins.configurationbackup.backuplocation = ConfigText(default = '/media/hdd/', visible_width = 50, fixed_size = False)
44 config.plugins.configurationbackup.backupdirs = ConfigLocations(default=['/etc/enigma2/', '/etc/network/interfaces', '/etc/wpa_supplicant.conf', '/etc/resolv.conf', '/etc/default_gw', '/etc/hostname'])
45
46 def write_cache(cache_file, cache_data):
47         #Does a cPickle dump
48         if not os_path.isdir( os_path.dirname(cache_file) ):
49                 try:
50                         mkdir( os_path.dirname(cache_file) )
51                 except OSError:
52                             print os_path.dirname(cache_file), 'is a file'
53         fd = open(cache_file, 'w')
54         dump(cache_data, fd, -1)
55         fd.close()
56
57 def valid_cache(cache_file, cache_ttl):
58         #See if the cache file exists and is still living
59         try:
60                 mtime = stat(cache_file)[ST_MTIME]
61         except:
62                 return 0
63         curr_time = time()
64         if (curr_time - mtime) > cache_ttl:
65                 return 0
66         else:
67                 return 1
68
69 def load_cache(cache_file):
70         #Does a cPickle load
71         fd = open(cache_file)
72         cache_data = load(fd)
73         fd.close()
74         return cache_data
75
76
77 class UpdatePluginMenu(Screen):
78         skin = """
79                 <screen name="UpdatePluginMenu" position="center,center" size="610,410" title="Software management" >
80                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
81                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
82                         <ePixmap pixmap="skin_default/border_menu_350.png" position="5,50" zPosition="1" size="350,300" transparent="1" alphatest="on" />
83                         <widget source="menu" render="Listbox" position="15,60" size="330,290" scrollbarMode="showOnDemand">
84                                 <convert type="TemplatedMultiContent">
85                                         {"template": [
86                                                         MultiContentEntryText(pos = (2, 2), size = (330, 24), flags = RT_HALIGN_LEFT, text = 1), # index 0 is the MenuText,
87                                                 ],
88                                         "fonts": [gFont("Regular", 22)],
89                                         "itemHeight": 25
90                                         }
91                                 </convert>
92                         </widget>
93                         <widget source="menu" render="Listbox" position="360,50" size="240,300" scrollbarMode="showNever" selectionDisabled="1">
94                                 <convert type="TemplatedMultiContent">
95                                         {"template": [
96                                                         MultiContentEntryText(pos = (2, 2), size = (240, 300), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, text = 2), # index 2 is the Description,
97                                                 ],
98                                         "fonts": [gFont("Regular", 22)],
99                                         "itemHeight": 300
100                                         }
101                                 </convert>
102                         </widget>
103                         <widget source="status" render="Label" position="5,360" zPosition="10" size="600,50" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
104                 </screen>"""
105                 
106         def __init__(self, session, args = 0):
107                 Screen.__init__(self, session)
108                 self.skin_path = plugin_path
109                 self.menu = args
110                 self.list = []
111                 self.oktext = _("\nPress OK on your remote control to continue.")
112                 self.text = ""
113                 self.backupdirs = ' '.join( config.plugins.configurationbackup.backupdirs.value )
114                 if self.menu == 0:
115                         self.list.append(("install-extensions", _("Manage extensions"), _("\nManage extensions or plugins for your Dreambox" ) + self.oktext, None))
116                         self.list.append(("software-update", _("Software update"), _("\nOnline update of your Dreambox software." ) + self.oktext, None))
117                         self.list.append(("software-restore", _("Software restore"), _("\nRestore your Dreambox with a new firmware." ) + self.oktext, None))
118                         self.list.append(("system-backup", _("Backup system settings"), _("\nBackup your Dreambox settings." ) + self.oktext, None))
119                         self.list.append(("system-restore",_("Restore system settings"), _("\nRestore your Dreambox settings." ) + self.oktext, None))
120                         self.list.append(("ipkg-install", _("Install local extension"),  _("\nScan for local extensions and install them." ) + self.oktext, None))
121                         for p in plugins.getPlugins(PluginDescriptor.WHERE_SOFTWAREMANAGER):
122                                 if p.__call__.has_key("SoftwareSupported"):
123                                         callFnc = p.__call__["SoftwareSupported"](None)
124                                         if callFnc is not None:
125                                                 if p.__call__.has_key("menuEntryName"):
126                                                         menuEntryName = p.__call__["menuEntryName"](None)
127                                                 else:
128                                                         menuEntryName = _('Extended Software')
129                                                 if p.__call__.has_key("menuEntryDescription"):
130                                                         menuEntryDescription = p.__call__["menuEntryDescription"](None)
131                                                 else:
132                                                         menuEntryDescription = _('Extended Software Plugin')
133                                                 self.list.append(('default-plugin', menuEntryName, menuEntryDescription + self.oktext, callFnc))
134                         if config.usage.setup_level.index >= 2: # expert+
135                                 self.list.append(("advanced", _("Advanced Options"), _("\nAdvanced options and settings." ) + self.oktext, None))
136                 elif self.menu == 1:
137                         self.list.append(("advancedrestore", _("Advanced restore"), _("\nRestore your backups by date." ) + self.oktext, None))
138                         self.list.append(("backuplocation", _("Choose backup location"),  _("\nSelect your backup device.\nCurrent device: " ) + config.plugins.configurationbackup.backuplocation.value + self.oktext, None))
139                         self.list.append(("backupfiles", _("Choose backup files"),  _("Select files for backup. Currently selected:\n" ) + self.backupdirs + self.oktext, None))
140                         #if config.usage.setup_level.index >= 2: # expert+
141                         #       self.list.append(("ipkg-manager", _("Packet management"),  _("\nView, install and remove available or installed packages." ) + self.oktext, None))
142                         self.list.append(("ipkg-source",_("Choose upgrade source"), _("\nEdit the upgrade source address." ) + self.oktext, None))
143                         for p in plugins.getPlugins(PluginDescriptor.WHERE_SOFTWAREMANAGER):
144                                 if p.__call__.has_key("AdvancedSoftwareSupported"):
145                                         callFnc = p.__call__["AdvancedSoftwareSupported"](None)
146                                         if callFnc is not None:
147                                                 if p.__call__.has_key("menuEntryName"):
148                                                         menuEntryName = p.__call__["menuEntryName"](None)
149                                                 else:
150                                                         menuEntryName = _('Advanced Software')
151                                                 if p.__call__.has_key("menuEntryDescription"):
152                                                         menuEntryDescription = p.__call__["menuEntryDescription"](None)
153                                                 else:
154                                                         menuEntryDescription = _('Advanced Software Plugin')
155                                                 self.list.append(('advanced-plugin', menuEntryName, menuEntryDescription + self.oktext, callFnc))
156
157                 self["menu"] = List(self.list)
158                 self["key_red"] = StaticText(_("Close"))
159                 self["status"] = StaticText("")
160
161                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions", "InfobarEPGActions"],
162                 {
163                         "ok": self.go,
164                         "back": self.close,
165                         "red": self.close,
166                 }, -1)
167                 self.onLayoutFinish.append(self.layoutFinished)
168                 self.backuppath = getBackupPath()
169                 self.backupfile = getBackupFilename()
170                 self.fullbackupfilename = self.backuppath + "/" + self.backupfile
171                 self.onShown.append(self.setWindowTitle)
172                 #self.onClose.append(self.cleanup)
173
174         def layoutFinished(self):
175                 idx = 0
176                 self["menu"].index = idx
177                 #self.getUpdateInfos()
178
179         def setWindowTitle(self):
180                 self.setTitle(_("Software management"))
181
182         def cleanup(self):
183                 iNetwork.stopPingConsole()
184                 iSoftwareTools.cleanupSoftwareTools()
185
186         def getUpdateInfos(self):
187                 self.text = ""
188                 if iSoftwareTools.NetworkConnectionAvailable == True:
189                         if iSoftwareTools.list_updating is False:
190                                 if iSoftwareTools.available_updates is not 0:
191                                         self.text = _("There are at least ") + str(iSoftwareTools.available_updates) + _(" updates available.")
192                                 else:
193                                         self.text = "" #_("There are no updates available.")
194                         else:
195                                 if iSoftwareTools.available_updates is not 0:
196                                         self.text = _("There are at least ") + str(iSoftwareTools.available_updates) + _(" updates available.")
197                                 else:
198                                         self.text = ""  #_("There are no updates available.")
199                                 self.text += "\n" + _("A search for available updates is currently in progress.")
200                 else:
201                         self.text = _("No network connection available.")
202                 self["status"].setText(self.text)
203
204
205         def go(self):
206                 #iNetwork.stopPingConsole()
207                 current = self["menu"].getCurrent()
208                 if current:
209                         currentEntry = current[0]
210                         if self.menu == 0:
211                                 if (currentEntry == "software-update"):
212                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to update your Dreambox?")+"\n"+_("\nAfter pressing OK, please wait!"))
213                                 elif (currentEntry == "software-restore"):
214                                         self.session.open(ImageWizard)
215                                 elif (currentEntry == "install-extensions"):
216                                         self.session.open(PluginManager, self.skin_path)
217                                 elif (currentEntry == "system-backup"):
218                                         self.session.openWithCallback(self.backupDone,BackupScreen, runBackup = True)
219                                 elif (currentEntry == "system-restore"):
220                                         if os_path.exists(self.fullbackupfilename):
221                                                 self.session.openWithCallback(self.startRestore, MessageBox, _("Are you sure you want to restore your Enigma2 backup?\nEnigma2 will restart after the restore"))
222                                         else:
223                                                 self.session.open(MessageBox, _("Sorry no backups found!"), MessageBox.TYPE_INFO, timeout = 10)
224                                 elif (currentEntry == "ipkg-install"):
225                                         try:
226                                                 from Plugins.Extensions.MediaScanner.plugin import main
227                                                 main(self.session)
228                                         except:
229                                                 self.session.open(MessageBox, _("Sorry MediaScanner is not installed!"), MessageBox.TYPE_INFO, timeout = 10)
230                                 elif (currentEntry == "default-plugin"):
231                                         self.extended = current[3]
232                                         self.extended(self.session, None)
233                                 elif (currentEntry == "advanced"):
234                                         self.session.open(UpdatePluginMenu, 1)
235                         elif self.menu == 1:
236                                 if (currentEntry == "ipkg-manager"):
237                                         self.session.open(PacketManager, self.skin_path)
238                                 elif (currentEntry == "backuplocation"):
239                                         parts = [ (r.description, r.mountpoint, self.session) for r in harddiskmanager.getMountedPartitions(onlyhotplug = False)]
240                                         for x in parts:
241                                                 if not access(x[1], F_OK|R_OK|W_OK) or x[1] == '/':
242                                                         parts.remove(x)
243                                         for x in parts:
244                                                 if x[1].startswith('/autofs/'):
245                                                         parts.remove(x)
246                                         if len(parts):
247                                                 self.session.openWithCallback(self.backuplocation_choosen, ChoiceBox, title = _("Please select medium to use as backup location"), list = parts)
248                                 elif (currentEntry == "backupfiles"):
249                                         self.session.openWithCallback(self.backupfiles_choosen,BackupSelection)
250                                 elif (currentEntry == "advancedrestore"):
251                                         self.session.open(RestoreMenu, self.skin_path)
252                                 elif (currentEntry == "ipkg-source"):
253                                         self.session.open(IPKGMenu, self.skin_path)
254                                 elif (currentEntry == "advanced-plugin"):
255                                         self.extended = current[3]
256                                         self.extended(self.session, None)
257
258         def backupfiles_choosen(self, ret):
259                 self.backupdirs = ' '.join( config.plugins.configurationbackup.backupdirs.value )
260
261         def backuplocation_choosen(self, option):
262                 if option is not None:
263                         config.plugins.configurationbackup.backuplocation.value = str(option[1])
264                 config.plugins.configurationbackup.backuplocation.save()
265                 config.plugins.configurationbackup.save()
266                 config.save()
267                 self.createBackupfolders()
268
269         def runUpgrade(self, result):
270                 if result:
271                         self.session.open(UpdatePlugin, self.skin_path)
272
273         def createBackupfolders(self):
274                 print "Creating backup folder if not already there..."
275                 self.backuppath = getBackupPath()
276                 try:
277                         if (os_path.exists(self.backuppath) == False):
278                                 makedirs(self.backuppath)
279                 except OSError:
280                         self.session.open(MessageBox, _("Sorry, your backup destination is not writeable.\n\nPlease choose another one."), MessageBox.TYPE_INFO, timeout = 10)
281
282         def backupDone(self,retval = None):
283                 if retval is True:
284                         self.session.open(MessageBox, _("Backup done."), MessageBox.TYPE_INFO, timeout = 10)
285                 else:
286                         self.session.open(MessageBox, _("Backup failed."), MessageBox.TYPE_INFO, timeout = 10)
287
288         def startRestore(self, ret = False):
289                 if (ret == True):
290                         self.exe = True
291                         self.session.open(RestoreScreen, runRestore = True)
292
293
294 class PluginManager(Screen, DreamInfoHandler):
295
296         skin = """
297                 <screen name="PluginManager" position="center,center" size="560,440" title="Extensions management" >
298                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
299                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
300                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
301                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
302                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
303                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
304                         <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
305                         <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
306                         <widget source="list" render="Listbox" position="5,50" size="550,360" scrollbarMode="showOnDemand">
307                                 <convert type="TemplatedMultiContent">
308                                 {"templates":
309                                         {"default": (51,[
310                                                         MultiContentEntryText(pos = (30, 1), size = (470, 24), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
311                                                         MultiContentEntryText(pos = (30, 25), size = (470, 24), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
312                                                         MultiContentEntryPixmapAlphaTest(pos = (475, 0), size = (48, 48), png = 5), # index 5 is the status pixmap
313                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 49), size = (550, 2), png = 6), # index 6 is the div pixmap
314                                                 ]),
315                                         "category": (40,[
316                                                         MultiContentEntryText(pos = (30, 0), size = (500, 22), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
317                                                         MultiContentEntryText(pos = (30, 22), size = (500, 16), font=2, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the description
318                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 38), size = (550, 2), png = 3), # index 3 is the div pixmap
319                                                 ])
320                                         },
321                                         "fonts": [gFont("Regular", 22),gFont("Regular", 20),gFont("Regular", 16)],
322                                         "itemHeight": 52
323                                 }
324                                 </convert>
325                         </widget>
326                         <widget source="status" render="Label" position="5,410" zPosition="10" size="540,30" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
327                 </screen>"""
328
329         def __init__(self, session, plugin_path, args = None):
330                 Screen.__init__(self, session)
331                 self.session = session
332                 self.skin_path = plugin_path
333
334                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions", "InfobarEPGActions", "HelpActions" ],
335                 {
336                         "ok": self.handleCurrent,
337                         "back": self.exit,
338                         "red": self.exit,
339                         "green": self.handleCurrent,
340                         "yellow": self.handleSelected,
341                         "showEventInfo": self.handleSelected,
342                         "displayHelp": self.handleHelp,
343                 }, -1)
344
345                 self.list = []
346                 self.statuslist = []
347                 self.selectedFiles = []
348                 self.categoryList = []
349                 self.packetlist = []
350                 self["list"] = List(self.list)
351                 self["key_red"] = StaticText(_("Close"))
352                 self["key_green"] = StaticText("")
353                 self["key_yellow"] = StaticText("")
354                 self["key_blue"] = StaticText("")
355                 self["status"] = StaticText("")
356
357                 self.cmdList = []
358                 self.oktext = _("\nAfter pressing OK, please wait!")
359                 if not self.selectionChanged in self["list"].onSelectionChanged:
360                         self["list"].onSelectionChanged.append(self.selectionChanged)
361
362                 self.currList = ""
363                 self.currentSelectedTag = None
364                 self.currentSelectedIndex = None
365                 self.currentSelectedPackage = None
366                 self.saved_currentSelectedPackage = None
367                 
368                 self.onShown.append(self.setWindowTitle)
369                 self.onLayoutFinish.append(self.getUpdateInfos)
370
371         def setWindowTitle(self):
372                 self.setTitle(_("Extensions management"))
373
374         def exit(self):
375                 if self.currList == "packages":
376                         self.currList = "category"
377                         self.currentSelectedTag = None
378                         self["list"].style = "category"
379                         self['list'].setList(self.categoryList)
380                         self["list"].setIndex(self.currentSelectedIndex)
381                         self["list"].updateList(self.categoryList)
382                         self.selectionChanged()
383                 else:
384                         iSoftwareTools.cleanupSoftwareTools()
385                         self.prepareInstall()
386                         if len(self.cmdList):
387                                 self.session.openWithCallback(self.runExecute, PluginManagerInfo, self.skin_path, self.cmdList)
388                         else:
389                                 self.close()
390
391         def handleHelp(self):
392                 if self.currList != "status":
393                         self.session.open(PluginManagerHelp, self.skin_path)
394
395         def setState(self,status = None):
396                 if status:
397                         self.currList = "status"
398                         self.statuslist = []
399                         self["key_green"].setText("")
400                         self["key_blue"].setText("")
401                         self["key_yellow"].setText("")
402                         divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
403                         if status == 'update':
404                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
405                                 self.statuslist.append(( _("Updating software catalog"), '', _("Searching for available updates. Please wait..." ),'', '', statuspng, divpng, None, '' ))
406                                 self["list"].style = "default"
407                                 self['list'].setList(self.statuslist)
408                         elif status == 'sync':
409                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
410                                 self.statuslist.append(( _("Package list update"), '', _("Searching for new installed or removed packages. Please wait..." ),'', '', statuspng, divpng, None, '' ))
411                                 self["list"].style = "default"
412                                 self['list'].setList(self.statuslist)
413                         elif status == 'error':
414                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
415                                 self.statuslist.append(( _("Error"), '', _("There was an error downloading the packetlist. Please try again." ),'', '', statuspng, divpng, None, '' ))
416                                 self["list"].style = "default"
417                                 self['list'].setList(self.statuslist)
418
419         def getUpdateInfos(self):
420                 self.setState('update')
421                 iSoftwareTools.getUpdates(self.getUpdateInfosCB)
422
423         def getUpdateInfosCB(self, retval = None):
424                 if retval is not None:
425                         if retval is True:
426                                 if iSoftwareTools.available_updates is not 0:
427                                         self["status"].setText(_("There are at least ") + str(iSoftwareTools.available_updates) + _(" updates available."))
428                                 else:
429                                         self["status"].setText(_("There are no updates available."))
430                         elif retval is False:
431                                 self["status"].setText(_("No network connection available."))
432                         self.rebuildList()
433
434         def rebuildList(self, retval = None):
435                 if self.currentSelectedTag is None:
436                         self.buildCategoryList()
437                 else:
438                         self.buildPacketList(self.currentSelectedTag)
439
440         def selectionChanged(self):
441                 current = self["list"].getCurrent()
442                 self["status"].setText("")
443                 if current:
444                         if self.currList == "packages":
445                                 self["key_red"].setText(_("Back"))
446                                 if current[4] == 'installed':
447                                         self["key_green"].setText(_("Uninstall"))
448                                 elif current[4] == 'installable':
449                                         self["key_green"].setText(_("Install"))
450                                 elif current[4] == 'remove':
451                                         self["key_green"].setText(_("Undo uninstall"))
452                                 elif current[4] == 'install':
453                                         self["key_green"].setText(_("Undo install"))
454                                 self["key_yellow"].setText(_("View details"))
455                                 self["key_blue"].setText("")
456                                 if len(self.selectedFiles) == 0 and iSoftwareTools.available_updates is not 0:
457                                         self["status"].setText(_("There are at least ") + str(iSoftwareTools.available_updates) + _(" updates available."))
458                                 elif len(self.selectedFiles) is not 0:
459                                         self["status"].setText(str(len(self.selectedFiles)) + _(" packages selected."))
460                                 else:
461                                         self["status"].setText(_("There are currently no outstanding actions."))
462                         elif self.currList == "category":
463                                 self["key_red"].setText(_("Close"))
464                                 self["key_green"].setText("")
465                                 self["key_yellow"].setText("")
466                                 self["key_blue"].setText("")
467                                 if len(self.selectedFiles) == 0 and iSoftwareTools.available_updates is not 0:
468                                         self["status"].setText(_("There are at least ") + str(iSoftwareTools.available_updates) + _(" updates available."))
469                                         self["key_yellow"].setText(_("Update"))
470                                 elif len(self.selectedFiles) is not 0:
471                                         self["status"].setText(str(len(self.selectedFiles)) + _(" packages selected."))
472                                         self["key_yellow"].setText(_("Process"))
473                                 else:
474                                         self["status"].setText(_("There are currently no outstanding actions."))
475
476         def getSelectionState(self, detailsFile):
477                 for entry in self.selectedFiles:
478                         if entry[0] == detailsFile:
479                                 return True
480                 return False
481
482         def handleCurrent(self):
483                 current = self["list"].getCurrent()
484                 if current:
485                         if self.currList == "category":
486                                 self.currentSelectedIndex = self["list"].index
487                                 selectedTag = current[2]
488                                 self.buildPacketList(selectedTag)
489                         elif self.currList == "packages":
490                                 if current[7] is not '':
491                                         idx = self["list"].getIndex()
492                                         detailsFile = self.list[idx][1]
493                                         if self.list[idx][7] == True:
494                                                 for entry in self.selectedFiles:
495                                                         if entry[0] == detailsFile:
496                                                                 self.selectedFiles.remove(entry)
497                                         else:
498                                                 alreadyinList = False
499                                                 for entry in self.selectedFiles:
500                                                         if entry[0] == detailsFile:
501                                                                 alreadyinList = True
502                                                 if not alreadyinList:
503                                                         self.selectedFiles.append((detailsFile,current[4],current[3]))
504                                                         self.currentSelectedPackage = ((detailsFile,current[4],current[3]))
505                                         if current[4] == 'installed':
506                                                 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'remove', True)
507                                         elif current[4] == 'installable':
508                                                 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'install', True)
509                                         elif current[4] == 'remove':
510                                                 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'installed', False)
511                                         elif current[4] == 'install':
512                                                 self.list[idx] = self.buildEntryComponent(current[0], current[1], current[2], current[3], 'installable',False)
513                                         self["list"].setList(self.list)
514                                         self["list"].setIndex(idx)
515                                         self["list"].updateList(self.list)
516                                         self.selectionChanged()
517
518         def handleSelected(self):
519                 current = self["list"].getCurrent()
520                 if current:
521                         if self.currList == "packages":
522                                 if current[7] is not '':
523                                         detailsfile = iSoftwareTools.directory[0] + "/" + current[1]
524                                         if (os_path.exists(detailsfile) == True):
525                                                 self.saved_currentSelectedPackage = self.currentSelectedPackage
526                                                 self.session.openWithCallback(self.detailsClosed, PluginDetails, self.skin_path, current)
527                                         else:
528                                                 self.session.open(MessageBox, _("Sorry, no Details available!"), MessageBox.TYPE_INFO, timeout = 10)
529                         elif self.currList == "category":
530                                 self.prepareInstall()
531                                 if len(self.cmdList):
532                                         self.session.openWithCallback(self.runExecute, PluginManagerInfo, self.skin_path, self.cmdList)
533
534         def detailsClosed(self, result = None):
535                 if result is not None:
536                         if result is not False:
537                                 self.setState('sync')
538                                 iSoftwareTools.lastDownloadDate = time()
539                                 for entry in self.selectedFiles:
540                                         if entry == self.saved_currentSelectedPackage:
541                                                 self.selectedFiles.remove(entry)
542                                 iSoftwareTools.startIpkgListInstalled(self.rebuildList)
543
544         def buildEntryComponent(self, name, details, description, packagename, state, selected = False):
545                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
546                 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
547                 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
548                 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
549                 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
550                 if state == 'installed':
551                         return((name, details, description, packagename, state, installedpng, divpng, selected))
552                 elif state == 'installable':
553                         return((name, details, description, packagename, state, installablepng, divpng, selected))
554                 elif state == 'remove':
555                         return((name, details, description, packagename, state, removepng, divpng, selected))
556                 elif state == 'install':
557                         return((name, details, description, packagename, state, installpng, divpng, selected))
558
559         def buildPacketList(self, categorytag = None):
560                 if categorytag is not None:
561                         self.currList = "packages"
562                         self.currentSelectedTag = categorytag
563                         self.packetlist = []
564                         for package in iSoftwareTools.packagesIndexlist[:]:
565                                 prerequisites = package[0]["prerequisites"]
566                                 if prerequisites.has_key("tag"):
567                                         for foundtag in prerequisites["tag"]:
568                                                 if categorytag == foundtag:
569                                                         attributes = package[0]["attributes"]
570                                                         if attributes.has_key("packagetype"):
571                                                                 if attributes["packagetype"] == "internal":
572                                                                         continue
573                                                                 self.packetlist.append([attributes["name"], attributes["details"], attributes["shortdescription"], attributes["packagename"]])
574                                                         else:
575                                                                 self.packetlist.append([attributes["name"], attributes["details"], attributes["shortdescription"], attributes["packagename"]])
576                         self.list = []
577                         for x in self.packetlist:
578                                 status = ""
579                                 name = x[0].strip()
580                                 details = x[1].strip()
581                                 description = x[2].strip()
582                                 packagename = x[3].strip()
583                                 selectState = self.getSelectionState(details)
584                                 if iSoftwareTools.installed_packetlist.has_key(packagename):
585                                         if selectState == True:
586                                                 status = "remove"
587                                         else:
588                                                 status = "installed"
589                                         self.list.append(self.buildEntryComponent(name, details, description, packagename, status, selected = selectState))
590                                 else:
591                                         if selectState == True:
592                                                 status = "install"
593                                         else:
594                                                 status = "installable"
595                                         self.list.append(self.buildEntryComponent(name, details, description, packagename, status, selected = selectState))
596                         if len(self.list):
597                                 self.list.sort(key=lambda x: x[0])
598                         self["list"].style = "default"
599                         self['list'].setList(self.list)
600                         self["list"].updateList(self.list)
601                         self.selectionChanged()
602
603         def buildCategoryList(self):
604                 self.currList = "category"
605                 self.categories = []
606                 self.categoryList = []
607                 for package in iSoftwareTools.packagesIndexlist[:]:
608                         prerequisites = package[0]["prerequisites"]
609                         if prerequisites.has_key("tag"):
610                                 for foundtag in prerequisites["tag"]:
611                                         attributes = package[0]["attributes"]
612                                         if foundtag not in self.categories:
613                                                 self.categories.append(foundtag)
614                                                 self.categoryList.append(self.buildCategoryComponent(foundtag))
615                 self.categoryList.sort(key=lambda x: x[0])
616                 self["list"].style = "category"
617                 self['list'].setList(self.categoryList)
618                 self["list"].updateList(self.categoryList)
619                 self.selectionChanged()
620
621         def buildCategoryComponent(self, tag = None):
622                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
623                 if tag is not None:
624                         if tag == 'System':
625                                 return(( _("System"), _("View list of available system extensions" ), tag, divpng ))
626                         elif tag == 'Skin':
627                                 return(( _("Skins"), _("View list of available skins" ), tag, divpng ))
628                         elif tag == 'Recording':
629                                 return(( _("Recordings"), _("View list of available recording extensions" ), tag, divpng ))
630                         elif tag == 'Network':
631                                 return(( _("Network"), _("View list of available networking extensions" ), tag, divpng ))
632                         elif tag == 'CI':
633                                 return(( _("CommonInterface"), _("View list of available CommonInterface extensions" ), tag, divpng ))
634                         elif tag == 'Default':
635                                 return(( _("Default Settings"), _("View list of available default settings" ), tag, divpng ))
636                         elif tag == 'SAT':
637                                 return(( _("Satteliteequipment"), _("View list of available Satteliteequipment extensions." ), tag, divpng ))
638                         elif tag == 'Software':
639                                 return(( _("Software"), _("View list of available software extensions" ), tag, divpng ))
640                         elif tag == 'Multimedia':
641                                 return(( _("Multimedia"), _("View list of available multimedia extensions." ), tag, divpng ))
642                         elif tag == 'Display':
643                                 return(( _("Display and Userinterface"), _("View list of available Display and Userinterface extensions." ), tag, divpng ))
644                         elif tag == 'EPG':
645                                 return(( _("Electronic Program Guide"), _("View list of available EPG extensions." ), tag, divpng ))
646                         elif tag == 'Communication':
647                                 return(( _("Communication"), _("View list of available communication extensions." ), tag, divpng ))
648                         else: # dynamically generate non existent tags
649                                 return(( str(tag), _("View list of available ") + str(tag) + _(" extensions." ), tag, divpng ))
650
651         def prepareInstall(self):
652                 self.cmdList = []
653                 if iSoftwareTools.available_updates > 0:
654                         self.cmdList.append((IpkgComponent.CMD_UPGRADE, { "test_only": False }))
655                 if self.selectedFiles and len(self.selectedFiles):
656                         for plugin in self.selectedFiles:
657                                 detailsfile = iSoftwareTools.directory[0] + "/" + plugin[0]
658                                 if (os_path.exists(detailsfile) == True):
659                                         iSoftwareTools.fillPackageDetails(plugin[0])
660                                         self.package = iSoftwareTools.packageDetails[0]
661                                         if self.package[0].has_key("attributes"):
662                                                 self.attributes = self.package[0]["attributes"]
663                                         if self.attributes.has_key("package"):
664                                                 self.packagefiles = self.attributes["package"]
665                                         if plugin[1] == 'installed':
666                                                 if self.packagefiles:
667                                                         for package in self.packagefiles[:]:
668                                                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
669                                                 else:
670                                                         self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
671                                         else:
672                                                 if self.packagefiles:
673                                                         for package in self.packagefiles[:]:
674                                                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
675                                                 else:
676                                                         self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
677                                 else:
678                                         if plugin[1] == 'installed':
679                                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
680                                         else:
681                                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
682
683         def runExecute(self, result = None):
684                 if result is not None:
685                         if result[0] is True:
686                                 self.session.openWithCallback(self.runExecuteFinished, Ipkg, cmdList = self.cmdList)
687                         elif result[0] is False:
688                                 self.cmdList = result[1]
689                                 self.session.openWithCallback(self.runExecuteFinished, Ipkg, cmdList = self.cmdList)
690                 else:
691                         self.close()
692
693         def runExecuteFinished(self):
694                 self.session.openWithCallback(self.ExecuteReboot, MessageBox, _("Install or remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
695
696         def ExecuteReboot(self, result):
697                 print "RESULT im ExecuteReboot",result
698                 if result is None:
699                         return
700                 if result is False:
701                         self.reloadPluginlist()
702                         self.selectedFiles = []
703                         self.detailsClosed(True)
704                 if result:
705                         quitMainloop(3)
706
707         def reloadPluginlist(self):
708                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
709
710
711 class PluginManagerInfo(Screen):
712         skin = """
713                 <screen name="PluginManagerInfo" position="center,center" size="560,450" title="Plugin manager activity information" >
714                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
715                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
716                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
717                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
718                         <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
719                                 <convert type="TemplatedMultiContent">
720                                         {"template": [
721                                                         MultiContentEntryText(pos = (50, 0), size = (150, 26), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
722                                                         MultiContentEntryText(pos = (50, 27), size = (540, 23), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
723                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
724                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 48), size = (550, 2), png = 3), # index 3 is the div pixmap
725                                                 ],
726                                         "fonts": [gFont("Regular", 24),gFont("Regular", 22)],
727                                         "itemHeight": 50
728                                         }
729                                 </convert>
730                         </widget>
731                         <ePixmap pixmap="skin_default/div-h.png" position="0,404" zPosition="10" size="560,2" transparent="1" alphatest="on" />
732                         <widget source="status" render="Label" position="5,408" zPosition="10" size="550,44" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
733                 </screen>"""
734
735         def __init__(self, session, plugin_path, cmdlist = None):
736                 Screen.__init__(self, session)
737                 self.session = session
738                 self.skin_path = plugin_path
739                 self.cmdlist = cmdlist
740
741                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
742                 {
743                         "ok": self.process_all,
744                         "back": self.exit,
745                         "red": self.exit,
746                         "green": self.process_extensions,
747                 }, -1)
748
749                 self.list = []
750                 self["list"] = List(self.list)
751                 self["key_red"] = StaticText(_("Cancel"))
752                 self["key_green"] = StaticText(_("Only extensions."))
753                 self["status"] = StaticText(_("Following tasks will be done after you press OK!"))
754
755                 self.onShown.append(self.setWindowTitle)
756                 self.onLayoutFinish.append(self.rebuildList)
757
758         def setWindowTitle(self):
759                 self.setTitle(_("Plugin manager activity information"))
760
761         def rebuildList(self):
762                 self.list = []
763                 if self.cmdlist is not None:
764                         for entry in self.cmdlist:
765                                 action = ""
766                                 info = ""
767                                 cmd = entry[0]
768                                 if cmd == 0:
769                                         action = 'install'
770                                 elif cmd == 2:
771                                         action = 'remove'
772                                 else:
773                                         action = 'upgrade'
774                                 args = entry[1]
775                                 if cmd == 0:
776                                         info = args['package']
777                                 elif cmd == 2:
778                                         info = args['package']
779                                 else:
780                                         info = _("Dreambox software because updates are available.")
781
782                                 self.list.append(self.buildEntryComponent(action,info))
783                         self['list'].setList(self.list)
784                         self['list'].updateList(self.list)
785
786         def buildEntryComponent(self, action,info):
787                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
788                 upgradepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
789                 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
790                 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
791                 if action == 'install':
792                         return(( _('Installing'), info, installpng, divpng))
793                 elif action == 'remove':
794                         return(( _('Removing'), info, removepng, divpng))
795                 else:
796                         return(( _('Upgrading'), info, upgradepng, divpng))
797
798         def exit(self):
799                 self.close()
800
801         def process_all(self):
802                 self.close((True,None))
803
804         def process_extensions(self):
805                 self.list = []
806                 if self.cmdlist is not None:
807                         for entry in self.cmdlist:
808                                 cmd = entry[0]
809                                 if entry[0] in (0,2):
810                                         self.list.append((entry))
811                 self.close((False,self.list))
812
813
814 class PluginManagerHelp(Screen):
815         skin = """
816                 <screen name="PluginManagerHelp" position="center,center" size="560,450" title="Plugin manager help" >
817                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
818                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
819                         <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
820                                 <convert type="TemplatedMultiContent">
821                                         {"template": [
822                                                         MultiContentEntryText(pos = (50, 0), size = (150, 26), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
823                                                         MultiContentEntryText(pos = (50, 27), size = (540, 23), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
824                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
825                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 48), size = (550, 2), png = 3), # index 3 is the div pixmap
826                                                 ],
827                                         "fonts": [gFont("Regular", 24),gFont("Regular", 22)],
828                                         "itemHeight": 50
829                                         }
830                                 </convert>
831                         </widget>
832                         <ePixmap pixmap="skin_default/div-h.png" position="0,404" zPosition="10" size="560,2" transparent="1" alphatest="on" />
833                         <widget source="status" render="Label" position="5,408" zPosition="10" size="550,44" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
834                 </screen>"""
835
836         def __init__(self, session, plugin_path):
837                 Screen.__init__(self, session)
838                 self.session = session
839                 self.skin_path = plugin_path
840
841                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
842                 {
843                         "back": self.exit,
844                         "red": self.exit,
845                 }, -1)
846
847                 self.list = []
848                 self["list"] = List(self.list)
849                 self["key_red"] = StaticText(_("Close"))
850                 self["status"] = StaticText(_("A small overview of the available icon states and actions."))
851
852                 self.onShown.append(self.setWindowTitle)
853                 self.onLayoutFinish.append(self.rebuildList)
854
855         def setWindowTitle(self):
856                 self.setTitle(_("Plugin manager help"))
857
858         def rebuildList(self):
859                 self.list = []
860                 self.list.append(self.buildEntryComponent('install'))
861                 self.list.append(self.buildEntryComponent('installable'))
862                 self.list.append(self.buildEntryComponent('installed'))
863                 self.list.append(self.buildEntryComponent('remove'))
864                 self['list'].setList(self.list)
865                 self['list'].updateList(self.list)
866
867         def buildEntryComponent(self, state):
868                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
869                 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
870                 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
871                 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
872                 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
873
874                 if state == 'installed':
875                         return(( _('This plugin is installed.'), _('You can remove this plugin.'), installedpng, divpng))
876                 elif state == 'installable':
877                         return(( _('This plugin is not installed.'), _('You can install this plugin.'), installablepng, divpng))
878                 elif state == 'install':
879                         return(( _('This plugin will be installed.'), _('You can cancel the installation.'), installpng, divpng))
880                 elif state == 'remove':
881                         return(( _('This plugin will be removed.'), _('You can cancel the removal.'), removepng, divpng))
882
883         def exit(self):
884                 self.close()
885
886
887 class PluginDetails(Screen, DreamInfoHandler):
888         skin = """
889                 <screen name="PluginDetails" position="center,center" size="600,440" title="Plugin details" >
890                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
891                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
892                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
893                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
894                         <widget source="author" render="Label" position="10,50" size="500,25" zPosition="10" font="Regular;21" transparent="1" />
895                         <widget name="statuspic" position="550,40" size="48,48" alphatest="on"/>
896                         <widget name="divpic" position="0,80" size="600,2" alphatest="on"/>
897                         <widget name="detailtext" position="10,90" size="270,330" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top"/>
898                         <widget name="screenshot" position="290,90" size="300,330" alphatest="on"/>
899                 </screen>"""
900         def __init__(self, session, plugin_path, packagedata = None):
901                 Screen.__init__(self, session)
902                 self.skin_path = plugin_path
903                 self.language = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
904                 self.attributes = None
905                 self.translatedAttributes = None
906                 DreamInfoHandler.__init__(self, self.statusCallback, blocking = False, language = self.language)
907                 self.directory = resolveFilename(SCOPE_METADIR)
908                 if packagedata:
909                         self.pluginname = packagedata[0]
910                         self.details = packagedata[1]
911                         self.pluginstate = packagedata[4]
912                         self.statuspicinstance = packagedata[5]
913                         self.divpicinstance = packagedata[6]
914                         self.fillPackageDetails(self.details)
915
916                 self.thumbnail = ""
917
918                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
919                 {
920                         "back": self.exit,
921                         "red": self.exit,
922                         "green": self.go,
923                         "up": self.pageUp,
924                         "down": self.pageDown,
925                         "left": self.pageUp,
926                         "right": self.pageDown,
927                 }, -1)
928
929                 self["key_red"] = StaticText(_("Close"))
930                 self["key_green"] = StaticText("")
931                 self["author"] = StaticText()
932                 self["statuspic"] = Pixmap()
933                 self["divpic"] = Pixmap()
934                 self["screenshot"] = Pixmap()
935                 self["detailtext"] = ScrollLabel()
936
937                 self["statuspic"].hide()
938                 self["screenshot"].hide()
939                 self["divpic"].hide()
940
941                 self.package = self.packageDetails[0]
942                 if self.package[0].has_key("attributes"):
943                         self.attributes = self.package[0]["attributes"]
944                 if self.package[0].has_key("translation"):
945                         self.translatedAttributes = self.package[0]["translation"]
946
947                 self.cmdList = []
948                 self.oktext = _("\nAfter pressing OK, please wait!")
949                 self.picload = ePicLoad()
950                 self.picload.PictureData.get().append(self.paintScreenshotPixmapCB)
951                 self.onShown.append(self.setWindowTitle)
952                 self.onLayoutFinish.append(self.setInfos)
953
954         def setWindowTitle(self):
955                 self.setTitle(_("Details for extension: " + self.pluginname))
956
957         def exit(self):
958                 self.close(False)
959
960         def pageUp(self):
961                 self["detailtext"].pageUp()
962
963         def pageDown(self):
964                 self["detailtext"].pageDown()
965
966         def statusCallback(self, status, progress):
967                 pass
968
969         def setInfos(self):
970                 if self.translatedAttributes.has_key("name"):
971                         self.pluginname = self.translatedAttributes["name"]
972                 elif self.attributes.has_key("name"):
973                         self.pluginname = self.attributes["name"]
974                 else:
975                         self.pluginname = _("unknown")
976
977                 if self.translatedAttributes.has_key("author"):
978                         self.author = self.translatedAttributes["author"]
979                 elif self.attributes.has_key("author"):
980                         self.author = self.attributes["author"]
981                 else:
982                         self.author = _("unknown")
983
984                 if self.translatedAttributes.has_key("description"):
985                         self.description = self.translatedAttributes["description"]
986                 elif self.attributes.has_key("description"):
987                         self.description = self.attributes["description"]
988                 else:
989                         self.description = _("No description available.")
990
991                 if self.translatedAttributes.has_key("screenshot"):
992                         self.loadThumbnail(self.translatedAttributes)
993                 else:
994                         self.loadThumbnail(self.attributes)
995
996                 self["author"].setText(_("Author: ") + self.author)
997                 self["detailtext"].setText(self.description.strip())
998                 if self.pluginstate in ('installable', 'install'):
999                         self["key_green"].setText(_("Install"))
1000                 else:
1001                         self["key_green"].setText(_("Remove"))
1002
1003         def loadThumbnail(self, entry):
1004                 thumbnailUrl = None
1005                 if entry.has_key("screenshot"):
1006                         thumbnailUrl = entry["screenshot"]
1007                 if thumbnailUrl is not None:
1008                         self.thumbnail = "/tmp/" + thumbnailUrl.split('/')[-1]
1009                         print "[PluginDetails] downloading screenshot " + thumbnailUrl + " to " + self.thumbnail
1010                         client.downloadPage(thumbnailUrl,self.thumbnail).addCallback(self.setThumbnail).addErrback(self.fetchFailed)
1011                 else:
1012                         self.setThumbnail(noScreenshot = True)
1013
1014         def setThumbnail(self, noScreenshot = False):
1015                 if not noScreenshot:
1016                         filename = self.thumbnail
1017                 else:
1018                         filename = resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/noprev.png")
1019
1020                 sc = AVSwitch().getFramebufferScale()
1021                 self.picload.setPara((self["screenshot"].instance.size().width(), self["screenshot"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
1022                 self.picload.startDecode(filename)
1023
1024                 if self.statuspicinstance != None:
1025                         self["statuspic"].instance.setPixmap(self.statuspicinstance.__deref__())
1026                         self["statuspic"].show()
1027                 if self.divpicinstance != None:
1028                         self["divpic"].instance.setPixmap(self.divpicinstance.__deref__())
1029                         self["divpic"].show()
1030
1031         def paintScreenshotPixmapCB(self, picInfo=None):
1032                 ptr = self.picload.getData()
1033                 if ptr != None:
1034                         self["screenshot"].instance.setPixmap(ptr.__deref__())
1035                         self["screenshot"].show()
1036                 else:
1037                         self.setThumbnail(noScreenshot = True)
1038
1039         def go(self):
1040                 if self.attributes.has_key("package"):
1041                         self.packagefiles = self.attributes["package"]
1042                 self.cmdList = []
1043                 if self.pluginstate in ('installed', 'remove'):
1044                         if self.packagefiles:
1045                                 for package in self.packagefiles[:]:
1046                                         self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
1047                                         if len(self.cmdList):
1048                                                 self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + self.pluginname + "\n" + self.oktext)
1049                 else:
1050                         if self.packagefiles:
1051                                 for package in self.packagefiles[:]:
1052                                         self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
1053                                         if len(self.cmdList):
1054                                                 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + self.pluginname + "\n" + self.oktext)
1055
1056         def runUpgrade(self, result):
1057                 if result:
1058                         self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
1059
1060         def runUpgradeFinished(self):
1061                 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Installation finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1062
1063         def UpgradeReboot(self, result):
1064                 if result is None:
1065                         return
1066                 if result is False:
1067                         self.close(True)
1068                 if result:
1069                         quitMainloop(3)
1070
1071         def runRemove(self, result):
1072                 if result:
1073                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
1074
1075         def runRemoveFinished(self):
1076                 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1077
1078         def RemoveReboot(self, result):
1079                 if result is None:
1080                         return
1081                 if result is False:
1082                         self.close(True)
1083                 if result:
1084                         quitMainloop(3)
1085
1086         def reloadPluginlist(self):
1087                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1088
1089         def fetchFailed(self,string):
1090                 self.setThumbnail(noScreenshot = True)
1091                 print "[PluginDetails] fetch failed " + string.getErrorMessage()
1092
1093
1094 class UpdatePlugin(Screen):
1095         skin = """
1096                 <screen name="UpdatePlugin" position="center,center" size="550,200" title="Software update" >
1097                         <widget name="activityslider" position="0,0" size="550,5"  />
1098                         <widget name="slider" position="0,150" size="550,30"  />
1099                         <widget source="package" render="Label" position="10,30" size="540,20" font="Regular;18" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1100                         <widget source="status" render="Label" position="10,60" size="540,45" font="Regular;20" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1101                 </screen>"""
1102
1103         def __init__(self, session, args = None):
1104                 Screen.__init__(self, session)
1105
1106                 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
1107
1108                 self.slider = Slider(0, 4)
1109                 self["slider"] = self.slider
1110                 self.activityslider = Slider(0, 100)
1111                 self["activityslider"] = self.activityslider
1112                 self.status = StaticText(_("Upgrading Dreambox... Please wait"))
1113                 self["status"] = self.status
1114                 self.package = StaticText()
1115                 self["package"] = self.package
1116
1117                 self.packages = 0
1118                 self.error = 0
1119
1120                 self.activity = 0
1121                 self.activityTimer = eTimer()
1122                 self.activityTimer.callback.append(self.doActivityTimer)
1123                 self.activityTimer.start(100, False)
1124
1125                 self.ipkg = IpkgComponent()
1126                 self.ipkg.addCallback(self.ipkgCallback)
1127
1128                 self.updating = True
1129                 self.package.setText(_("Package list update"))
1130                 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
1131
1132                 self["actions"] = ActionMap(["WizardActions"], 
1133                 {
1134                         "ok": self.exit,
1135                         "back": self.exit
1136                 }, -1)
1137
1138         def doActivityTimer(self):
1139                 self.activity += 1
1140                 if self.activity == 100:
1141                         self.activity = 0
1142                 self.activityslider.setValue(self.activity)
1143
1144         def ipkgCallback(self, event, param):
1145                 if event == IpkgComponent.EVENT_DOWNLOAD:
1146                         self.status.setText(_("Downloading"))
1147                 elif event == IpkgComponent.EVENT_UPGRADE:
1148                         if self.sliderPackages.has_key(param):
1149                                 self.slider.setValue(self.sliderPackages[param])
1150                         self.package.setText(param)
1151                         self.status.setText(_("Upgrading"))
1152                         self.packages += 1
1153                 elif event == IpkgComponent.EVENT_INSTALL:
1154                         self.package.setText(param)
1155                         self.status.setText(_("Installing"))
1156                         self.packages += 1
1157                 elif event == IpkgComponent.EVENT_CONFIGURING:
1158                         self.package.setText(param)
1159                         self.status.setText(_("Configuring"))
1160                 elif event == IpkgComponent.EVENT_MODIFIED:
1161                         self.session.openWithCallback(
1162                                 self.modificationCallback,
1163                                 MessageBox,
1164                                 _("A configuration file (%s) was modified since Installation.\nDo you want to keep your version?") % (param)
1165                         )
1166                 elif event == IpkgComponent.EVENT_ERROR:
1167                         self.error += 1
1168                 elif event == IpkgComponent.EVENT_DONE:
1169                         if self.updating:
1170                                 self.updating = False
1171                                 self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE, args = {'test_only': False})
1172                         elif self.error == 0:
1173                                 self.slider.setValue(4)
1174                                 
1175                                 self.activityTimer.stop()
1176                                 self.activityslider.setValue(0)
1177                                 
1178                                 self.package.setText("")
1179                                 self.status.setText(_("Done - Installed or upgraded %d packages") % self.packages)
1180                         else:
1181                                 self.activityTimer.stop()
1182                                 self.activityslider.setValue(0)
1183                                 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
1184                                 if self.packages == 0:
1185                                         error = _("No packages were upgraded yet. So you can check your network and try again.")
1186                                 if self.updating:
1187                                         error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
1188                                 self.status.setText(_("Error") +  " - " + error)
1189                 #print event, "-", param
1190                 pass
1191
1192         def modificationCallback(self, res):
1193                 self.ipkg.write(res and "N" or "Y")
1194
1195         def exit(self):
1196                 if not self.ipkg.isRunning():
1197                         if self.packages != 0 and self.error == 0:
1198                                 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"))
1199                         else:
1200                                 self.close()
1201
1202         def exitAnswer(self, result):
1203                 if result is not None and result:
1204                         quitMainloop(2)
1205                 self.close()
1206
1207
1208
1209 class IPKGMenu(Screen):
1210         skin = """
1211                 <screen name="IPKGMenu" position="center,center" size="560,400" title="Select upgrade source to edit." >
1212                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1213                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1214                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1215                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1216                         <widget name="filelist" position="5,50" size="550,340" scrollbarMode="showOnDemand" />
1217                 </screen>"""
1218
1219         def __init__(self, session, plugin_path):
1220                 Screen.__init__(self, session)
1221                 self.skin_path = plugin_path
1222                 
1223                 self["key_red"] = StaticText(_("Close"))
1224                 self["key_green"] = StaticText(_("Edit"))
1225
1226                 self.sel = []
1227                 self.val = []
1228                 self.entry = False
1229                 self.exe = False
1230                 
1231                 self.path = ""
1232
1233                 self["actions"] = NumberActionMap(["SetupActions"],
1234                 {
1235                         "ok": self.KeyOk,
1236                         "cancel": self.keyCancel
1237                 }, -1)
1238
1239                 self["shortcuts"] = ActionMap(["ShortcutActions"],
1240                 {
1241                         "red": self.keyCancel,
1242                         "green": self.KeyOk,
1243                 })
1244                 self.flist = []
1245                 self["filelist"] = MenuList(self.flist)
1246                 self.fill_list()
1247                 self.onLayoutFinish.append(self.layoutFinished)
1248
1249         def layoutFinished(self):
1250                 self.setWindowTitle()
1251
1252         def setWindowTitle(self):
1253                 self.setTitle(_("Select upgrade source to edit."))
1254
1255         def fill_list(self):
1256                 self.flist = []
1257                 self.path = '/etc/ipkg/'
1258                 if (os_path.exists(self.path) == False):
1259                         self.entry = False
1260                         return
1261                 for file in listdir(self.path):
1262                         if (file.endswith(".conf")):
1263                                 if file != 'arch.conf':
1264                                         self.flist.append((file))
1265                                         self.entry = True
1266                                         self["filelist"].l.setList(self.flist)
1267
1268         def KeyOk(self):
1269                 if (self.exe == False) and (self.entry == True):
1270                         self.sel = self["filelist"].getCurrent()
1271                         self.val = self.path + self.sel
1272                         self.session.open(IPKGSource, self.val)
1273
1274         def keyCancel(self):
1275                 self.close()
1276
1277         def Exit(self):
1278                 self.close()
1279
1280
1281 class IPKGSource(Screen):
1282         skin = """
1283                 <screen name="IPKGSource" position="center,center" size="560,80" title="Edit upgrade source url." >
1284                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1285                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1286                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1287                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1288                         <widget name="text" position="5,50" size="550,25" font="Regular;20" backgroundColor="background" foregroundColor="#cccccc" />
1289                 </screen>"""
1290
1291         def __init__(self, session, configfile = None):
1292                 Screen.__init__(self, session)
1293                 self.session = session
1294                 self.configfile = configfile
1295                 text = ""
1296                 if self.configfile:
1297                         try:
1298                                 fp = file(configfile, 'r')
1299                                 sources = fp.readlines()
1300                                 if sources:
1301                                         text = sources[0]
1302                                 fp.close()
1303                         except IOError:
1304                                 pass
1305
1306                 desk = getDesktop(0)
1307                 x= int(desk.size().width())
1308                 y= int(desk.size().height())
1309
1310                 self["key_red"] = StaticText(_("Cancel"))
1311                 self["key_green"] = StaticText(_("Save"))
1312
1313                 if (y>=720):
1314                         self["text"] = Input(text, maxSize=False, type=Input.TEXT)
1315                 else:
1316                         self["text"] = Input(text, maxSize=False, visible_width = 55, type=Input.TEXT)
1317
1318                 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "TextEntryActions", "KeyboardInputActions","ShortcutActions"], 
1319                 {
1320                         "ok": self.go,
1321                         "back": self.close,
1322                         "red": self.close,
1323                         "green": self.go,
1324                         "left": self.keyLeft,
1325                         "right": self.keyRight,
1326                         "home": self.keyHome,
1327                         "end": self.keyEnd,
1328                         "deleteForward": self.keyDeleteForward,
1329                         "deleteBackward": self.keyDeleteBackward,
1330                         "1": self.keyNumberGlobal,
1331                         "2": self.keyNumberGlobal,
1332                         "3": self.keyNumberGlobal,
1333                         "4": self.keyNumberGlobal,
1334                         "5": self.keyNumberGlobal,
1335                         "6": self.keyNumberGlobal,
1336                         "7": self.keyNumberGlobal,
1337                         "8": self.keyNumberGlobal,
1338                         "9": self.keyNumberGlobal,
1339                         "0": self.keyNumberGlobal
1340                 }, -1)
1341
1342                 self.onLayoutFinish.append(self.layoutFinished)
1343
1344         def layoutFinished(self):
1345                 self.setWindowTitle()
1346                 self["text"].right()
1347
1348         def setWindowTitle(self):
1349                 self.setTitle(_("Edit upgrade source url."))
1350
1351         def go(self):
1352                 text = self["text"].getText()
1353                 if text:
1354                         fp = file(self.configfile, 'w')
1355                         fp.write(text)
1356                         fp.write("\n")
1357                         fp.close()
1358                 self.close()
1359
1360         def keyLeft(self):
1361                 self["text"].left()
1362         
1363         def keyRight(self):
1364                 self["text"].right()
1365         
1366         def keyHome(self):
1367                 self["text"].home()
1368         
1369         def keyEnd(self):
1370                 self["text"].end()
1371         
1372         def keyDeleteForward(self):
1373                 self["text"].delete()
1374         
1375         def keyDeleteBackward(self):
1376                 self["text"].deleteBackward()
1377         
1378         def keyNumberGlobal(self, number):
1379                 self["text"].number(number)
1380
1381
1382 class PacketManager(Screen):
1383         skin = """
1384                 <screen name="PacketManager" position="center,center" size="530,420" title="Packet manager" >
1385                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1386                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1387                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1388                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1389                         <widget source="list" render="Listbox" position="5,50" size="520,365" scrollbarMode="showOnDemand">
1390                                 <convert type="TemplatedMultiContent">
1391                                         {"template": [
1392                                                         MultiContentEntryText(pos = (5, 1), size = (440, 28), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
1393                                                         MultiContentEntryText(pos = (5, 26), size = (440, 20), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
1394                                                         MultiContentEntryPixmapAlphaTest(pos = (445, 2), size = (48, 48), png = 4), # index 4 is the status pixmap
1395                                                         MultiContentEntryPixmapAlphaTest(pos = (5, 50), size = (510, 2), png = 5), # index 4 is the div pixmap
1396                                                 ],
1397                                         "fonts": [gFont("Regular", 22),gFont("Regular", 14)],
1398                                         "itemHeight": 52
1399                                         }
1400                                 </convert>
1401                         </widget>
1402                 </screen>"""
1403                 
1404         def __init__(self, session, plugin_path, args = None):
1405                 Screen.__init__(self, session)
1406                 self.session = session
1407                 self.skin_path = plugin_path
1408
1409                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"], 
1410                 {
1411                         "ok": self.go,
1412                         "back": self.exit,
1413                         "red": self.exit,
1414                         "green": self.reload,
1415                 }, -1)
1416                 
1417                 self.list = []
1418                 self.statuslist = []
1419                 self["list"] = List(self.list)
1420                 self["key_red"] = StaticText(_("Close"))
1421                 self["key_green"] = StaticText(_("Reload"))
1422
1423                 self.list_updating = True
1424                 self.packetlist = []
1425                 self.installed_packetlist = {}
1426                 self.Console = Console()
1427                 self.cmdList = []
1428                 self.cachelist = []
1429                 self.cache_ttl = 86400  #600 is default, 0 disables, Seconds cache is considered valid (24h should be ok for caching ipkgs)
1430                 self.cache_file = '/usr/lib/enigma2/python/Plugins/SystemPlugins/SoftwareManager/packetmanager.cache' #Path to cache directory   
1431                 self.oktext = _("\nAfter pressing OK, please wait!")
1432                 self.unwanted_extensions = ('-dbg', '-dev', '-doc', 'busybox')
1433
1434                 self.ipkg = IpkgComponent()
1435                 self.ipkg.addCallback(self.ipkgCallback)
1436                 self.onShown.append(self.setWindowTitle)
1437                 self.onLayoutFinish.append(self.rebuildList)
1438
1439         def exit(self):
1440                 self.ipkg.stop()
1441                 if self.Console is not None:
1442                         if len(self.Console.appContainers):
1443                                 for name in self.Console.appContainers.keys():
1444                                         self.Console.kill(name)
1445                 self.close()
1446
1447         def reload(self):
1448                 if (os_path.exists(self.cache_file) == True):
1449                         remove(self.cache_file)
1450                         self.list_updating = True
1451                         self.rebuildList()
1452                         
1453         def setWindowTitle(self):
1454                 self.setTitle(_("Packet manager"))
1455
1456         def setStatus(self,status = None):
1457                 if status:
1458                         self.statuslist = []
1459                         divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1460                         if status == 'update':
1461                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
1462                                 self.statuslist.append(( _("Package list update"), '', _("Trying to download a new packetlist. Please wait..." ),'',statuspng, divpng ))
1463                                 self['list'].setList(self.statuslist)   
1464                         elif status == 'error':
1465                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1466                                 self.statuslist.append(( _("Error"), '', _("There was an error downloading the packetlist. Please try again." ),'',statuspng, divpng ))
1467                                 self['list'].setList(self.statuslist)                           
1468
1469         def rebuildList(self):
1470                 self.setStatus('update')
1471                 self.inv_cache = 0
1472                 self.vc = valid_cache(self.cache_file, self.cache_ttl)
1473                 if self.cache_ttl > 0 and self.vc != 0:
1474                         try:
1475                                 self.buildPacketList()
1476                         except:
1477                                 self.inv_cache = 1
1478                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
1479                         self.run = 0
1480                         self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
1481
1482         def go(self, returnValue = None):
1483                 cur = self["list"].getCurrent()
1484                 if cur:
1485                         status = cur[3]
1486                         package = cur[0]
1487                         self.cmdList = []
1488                         if status == 'installed':
1489                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package }))
1490                                 if len(self.cmdList):
1491                                         self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + package + "\n" + self.oktext)
1492                         elif status == 'upgradeable':
1493                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
1494                                 if len(self.cmdList):
1495                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to upgrade the package:\n") + package + "\n" + self.oktext)
1496                         elif status == "installable":
1497                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
1498                                 if len(self.cmdList):
1499                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + package + "\n" + self.oktext)
1500
1501         def runRemove(self, result):
1502                 if result:
1503                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
1504
1505         def runRemoveFinished(self):
1506                 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1507
1508         def RemoveReboot(self, result):
1509                 if result is None:
1510                         return
1511                 if result is False:
1512                         cur = self["list"].getCurrent()
1513                         if cur:
1514                                 item = self['list'].getIndex()
1515                                 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installable')
1516                                 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installable']
1517                                 self['list'].setList(self.list)
1518                                 write_cache(self.cache_file, self.cachelist)
1519                                 self.reloadPluginlist()
1520                 if result:
1521                         quitMainloop(3)
1522
1523         def runUpgrade(self, result):
1524                 if result:
1525                         self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
1526
1527         def runUpgradeFinished(self):
1528                 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1529                 
1530         def UpgradeReboot(self, result):
1531                 if result is None:
1532                         return
1533                 if result is False:
1534                         cur = self["list"].getCurrent()
1535                         if cur:
1536                                 item = self['list'].getIndex()
1537                                 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installed')
1538                                 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installed']
1539                                 self['list'].setList(self.list)
1540                                 write_cache(self.cache_file, self.cachelist)
1541                                 self.reloadPluginlist()
1542                 if result:
1543                         quitMainloop(3)
1544
1545         def ipkgCallback(self, event, param):
1546                 if event == IpkgComponent.EVENT_ERROR:
1547                         self.list_updating = False
1548                         self.setStatus('error')
1549                 elif event == IpkgComponent.EVENT_DONE:
1550                         if self.list_updating:
1551                                 self.list_updating = False
1552                                 if not self.Console:
1553                                         self.Console = Console()
1554                                 cmd = "ipkg list"
1555                                 self.Console.ePopen(cmd, self.IpkgList_Finished)
1556                 #print event, "-", param
1557                 pass
1558
1559         def IpkgList_Finished(self, result, retval, extra_args = None):
1560                 if len(result):
1561                         self.packetlist = []
1562                         for x in result.splitlines():
1563                                 split = x.split(' - ')   #self.blacklisted_packages
1564                                 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
1565                                         self.packetlist.append([split[0].strip(), split[1].strip(),split[2].strip()])
1566                 if not self.Console:
1567                         self.Console = Console()
1568                 cmd = "ipkg list_installed"
1569                 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
1570
1571         def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
1572                 if len(result):
1573                         self.installed_packetlist = {}
1574                         for x in result.splitlines():
1575                                 split = x.split(' - ')
1576                                 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
1577                                         self.installed_packetlist[split[0].strip()] = split[1].strip()
1578                 self.buildPacketList()
1579
1580         def buildEntryComponent(self, name, version, description, state):
1581                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1582                 if state == 'installed':
1583                         installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
1584                         return((name, version, description, state, installedpng, divpng))       
1585                 elif state == 'upgradeable':
1586                         upgradeablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgradeable.png"))
1587                         return((name, version, description, state, upgradeablepng, divpng))     
1588                 else:
1589                         installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
1590                         return((name, version, description, state, installablepng, divpng))
1591
1592         def buildPacketList(self):
1593                 self.list = []
1594                 self.cachelist = []
1595
1596                 if self.cache_ttl > 0 and self.vc != 0:
1597                         print 'Loading packagelist cache from ',self.cache_file
1598                         try:
1599                                 self.cachelist = load_cache(self.cache_file)
1600                                 if len(self.cachelist) > 0:
1601                                         for x in self.cachelist:
1602                                                 self.list.append(self.buildEntryComponent(x[0], x[1], x[2], x[3]))
1603                                         self['list'].setList(self.list)
1604                         except:
1605                                 self.inv_cache = 1
1606
1607                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
1608                         print 'rebuilding fresh package list'
1609                         for x in self.packetlist:
1610                                 status = ""
1611                                 if self.installed_packetlist.has_key(x[0].strip()):
1612                                         if self.installed_packetlist[x[0].strip()] == x[1].strip():
1613                                                 status = "installed"
1614                                                 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
1615                                         else:
1616                                                 status = "upgradeable"
1617                                                 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
1618                                 else:
1619                                         status = "installable"
1620                                         self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
1621                                 if not any(x[0].strip().endswith(x) for x in self.unwanted_extensions):
1622                                         self.cachelist.append([x[0].strip(), x[1].strip(), x[2].strip(), status])
1623                         write_cache(self.cache_file, self.cachelist)
1624                         self['list'].setList(self.list)
1625
1626         def reloadPluginlist(self):
1627                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1628
1629 class IpkgInstaller(Screen):
1630         skin = """
1631                 <screen name="IpkgInstaller" position="center,center" size="550,450" title="Install extensions" >
1632                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1633                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1634                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
1635                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
1636                         <widget name="list" position="5,50" size="540,360" />
1637                         <ePixmap pixmap="skin_default/div-h.png" position="0,410" zPosition="10" size="560,2" transparent="1" alphatest="on" />
1638                         <widget source="introduction" render="Label" position="5,420" zPosition="10" size="550,30" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
1639                 </screen>"""
1640         
1641         def __init__(self, session, list):
1642                 Screen.__init__(self, session)
1643
1644                 self.list = SelectionList()
1645                 self["list"] = self.list
1646                 for listindex in range(len(list)):
1647                         self.list.addSelection(list[listindex], list[listindex], listindex, True)
1648
1649                 self["key_red"] = StaticText(_("Close"))
1650                 self["key_green"] = StaticText(_("Install"))
1651                 self["introduction"] = StaticText(_("Press OK to toggle the selection."))
1652                 
1653                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], 
1654                 {
1655                         "ok": self.list.toggleSelection, 
1656                         "cancel": self.close,
1657                         "red": self.close,
1658                         "green": self.install
1659                 }, -1)
1660
1661         def install(self):
1662                 list = self.list.getSelectionsList()
1663                 cmdList = []
1664                 for item in list:
1665                         cmdList.append((IpkgComponent.CMD_INSTALL, { "package": item[1] }))
1666                 self.session.open(Ipkg, cmdList = cmdList)
1667
1668
1669 def filescan_open(list, session, **kwargs):
1670         filelist = [x.path for x in list]
1671         session.open(IpkgInstaller, filelist) # list
1672
1673 def filescan(**kwargs):
1674         from Components.Scanner import Scanner, ScanPath
1675         return \
1676                 Scanner(mimetypes = ["application/x-debian-package"], 
1677                         paths_to_scan = 
1678                                 [
1679                                         ScanPath(path = "ipk", with_subdirs = True), 
1680                                         ScanPath(path = "", with_subdirs = False), 
1681                                 ], 
1682                         name = "Ipkg", 
1683                         description = _("Install extensions."),
1684                         openfnc = filescan_open, )
1685
1686
1687
1688 def UpgradeMain(session, **kwargs):
1689         session.open(UpdatePluginMenu)
1690
1691 def startSetup(menuid):
1692         if menuid != "setup": 
1693                 return [ ]
1694         return [(_("Software management"), UpgradeMain, "software_manager", 50)]
1695
1696 def autostart(reason, **kwargs):
1697         if reason is True:
1698                 iSoftwareTools.startSoftwareTools()
1699
1700 def Plugins(path, **kwargs):
1701         global plugin_path
1702         plugin_path = path
1703         list = [
1704                 PluginDescriptor(where = [PluginDescriptor.WHERE_NETWORKCONFIG_READ], fnc = autostart),
1705                 PluginDescriptor(name=_("Software management"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_MENU, fnc=startSetup), 
1706                 PluginDescriptor(name=_("Ipkg"), where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
1707         ]
1708         if config.usage.setup_level.index >= 2: # expert+
1709                 list.append(PluginDescriptor(name=_("Software management"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=UpgradeMain))
1710         return list