SoftwareManager/plugin.py: - enable extensions management inside Software manager.
[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                                                         print "ATTRIBUTES",attributes
571                                                         if attributes.has_key("packagetype"):
572                                                                 print "PACKAGETYPE",attributes["packagetype"]
573                                                                 if attributes["packagetype"] == "internal":
574                                                                         continue
575                                                                 self.packetlist.append([attributes["name"], attributes["details"], attributes["shortdescription"], attributes["packagename"]])
576                                                         else:
577                                                                 self.packetlist.append([attributes["name"], attributes["details"], attributes["shortdescription"], attributes["packagename"]])
578                         self.list = []
579                         for x in self.packetlist:
580                                 status = ""
581                                 name = x[0].strip()
582                                 details = x[1].strip()
583                                 description = x[2].strip()
584                                 packagename = x[3].strip()
585                                 selectState = self.getSelectionState(details)
586                                 if iSoftwareTools.installed_packetlist.has_key(packagename):
587                                         if selectState == True:
588                                                 status = "remove"
589                                         else:
590                                                 status = "installed"
591                                         self.list.append(self.buildEntryComponent(name, details, description, packagename, status, selected = selectState))
592                                 else:
593                                         if selectState == True:
594                                                 status = "install"
595                                         else:
596                                                 status = "installable"
597                                         self.list.append(self.buildEntryComponent(name, details, description, packagename, status, selected = selectState))
598                         if len(self.list):
599                                 self.list.sort(key=lambda x: x[0])
600                         self["list"].style = "default"
601                         self['list'].setList(self.list)
602                         self["list"].updateList(self.list)
603                         self.selectionChanged()
604
605         def buildCategoryList(self):
606                 self.currList = "category"
607                 self.categories = []
608                 self.categoryList = []
609                 for package in iSoftwareTools.packagesIndexlist[:]:
610                         prerequisites = package[0]["prerequisites"]
611                         if prerequisites.has_key("tag"):
612                                 for foundtag in prerequisites["tag"]:
613                                         attributes = package[0]["attributes"]
614                                         if foundtag not in self.categories:
615                                                 self.categories.append(foundtag)
616                                                 self.categoryList.append(self.buildCategoryComponent(foundtag))
617                 self.categoryList.sort(key=lambda x: x[0])
618                 self["list"].style = "category"
619                 self['list'].setList(self.categoryList)
620                 self["list"].updateList(self.categoryList)
621                 self.selectionChanged()
622
623         def buildCategoryComponent(self, tag = None):
624                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
625                 if tag is not None:
626                         if tag == 'System':
627                                 return(( _("System"), _("View list of available system extensions" ), tag, divpng ))
628                         elif tag == 'Skin':
629                                 return(( _("Skins"), _("View list of available skins" ), tag, divpng ))
630                         elif tag == 'Recording':
631                                 return(( _("Recordings"), _("View list of available recording extensions" ), tag, divpng ))
632                         elif tag == 'Network':
633                                 return(( _("Network"), _("View list of available networking extensions" ), tag, divpng ))
634                         elif tag == 'CI':
635                                 return(( _("CommonInterface"), _("View list of available CommonInterface extensions" ), tag, divpng ))
636                         elif tag == 'Default':
637                                 return(( _("Default Settings"), _("View list of available default settings" ), tag, divpng ))
638                         elif tag == 'SAT':
639                                 return(( _("Satteliteequipment"), _("View list of available Satteliteequipment extensions." ), tag, divpng ))
640                         elif tag == 'Software':
641                                 return(( _("Software"), _("View list of available software extensions" ), tag, divpng ))
642                         elif tag == 'Multimedia':
643                                 return(( _("Multimedia"), _("View list of available multimedia extensions." ), tag, divpng ))
644                         elif tag == 'Display':
645                                 return(( _("Display and Userinterface"), _("View list of available Display and Userinterface extensions." ), tag, divpng ))
646                         elif tag == 'EPG':
647                                 return(( _("Electronic Program Guide"), _("View list of available EPG extensions." ), tag, divpng ))
648                         elif tag == 'Communication':
649                                 return(( _("Communication"), _("View list of available communication extensions." ), tag, divpng ))
650                         else: # dynamically generate non existent tags
651                                 return(( str(tag), _("View list of available ") + str(tag) + _(" extensions." ), tag, divpng ))
652
653         def prepareInstall(self):
654                 self.cmdList = []
655                 if iSoftwareTools.available_updates > 0:
656                         self.cmdList.append((IpkgComponent.CMD_UPGRADE, { "test_only": False }))
657                 if self.selectedFiles and len(self.selectedFiles):
658                         for plugin in self.selectedFiles:
659                                 detailsfile = iSoftwareTools.directory[0] + "/" + plugin[0]
660                                 if (os_path.exists(detailsfile) == True):
661                                         iSoftwareTools.fillPackageDetails(plugin[0])
662                                         self.package = iSoftwareTools.packageDetails[0]
663                                         if self.package[0].has_key("attributes"):
664                                                 self.attributes = self.package[0]["attributes"]
665                                         if self.attributes.has_key("package"):
666                                                 self.packagefiles = self.attributes["package"]
667                                         if plugin[1] == 'installed':
668                                                 if self.packagefiles:
669                                                         for package in self.packagefiles[:]:
670                                                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
671                                                 else:
672                                                         self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
673                                         else:
674                                                 if self.packagefiles:
675                                                         for package in self.packagefiles[:]:
676                                                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
677                                                 else:
678                                                         self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
679                                 else:
680                                         if plugin[1] == 'installed':
681                                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": plugin[2] }))
682                                         else:
683                                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": plugin[2] }))
684
685         def runExecute(self, result = None):
686                 if result is not None:
687                         if result[0] is True:
688                                 self.session.openWithCallback(self.runExecuteFinished, Ipkg, cmdList = self.cmdList)
689                         elif result[0] is False:
690                                 self.cmdList = result[1]
691                                 self.session.openWithCallback(self.runExecuteFinished, Ipkg, cmdList = self.cmdList)
692                 else:
693                         self.close()
694
695         def runExecuteFinished(self):
696                 self.session.openWithCallback(self.ExecuteReboot, MessageBox, _("Install or remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
697
698         def ExecuteReboot(self, result):
699                 if result is None:
700                         return
701                 if result is False:
702                         self.reloadPluginlist()
703                         self.selectedFiles = None
704                         self.detailsClosed(True)
705                 if result:
706                         quitMainloop(3)
707
708         def reloadPluginlist(self):
709                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
710
711
712 class PluginManagerInfo(Screen):
713         skin = """
714                 <screen name="PluginManagerInfo" position="center,center" size="560,450" title="Plugin manager activity information" >
715                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
716                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
717                         <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" />
718                         <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" />
719                         <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
720                                 <convert type="TemplatedMultiContent">
721                                         {"template": [
722                                                         MultiContentEntryText(pos = (50, 0), size = (150, 26), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
723                                                         MultiContentEntryText(pos = (50, 27), size = (540, 23), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
724                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
725                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 48), size = (550, 2), png = 3), # index 3 is the div pixmap
726                                                 ],
727                                         "fonts": [gFont("Regular", 24),gFont("Regular", 22)],
728                                         "itemHeight": 50
729                                         }
730                                 </convert>
731                         </widget>
732                         <ePixmap pixmap="skin_default/div-h.png" position="0,404" zPosition="10" size="560,2" transparent="1" alphatest="on" />
733                         <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" />
734                 </screen>"""
735
736         def __init__(self, session, plugin_path, cmdlist = None):
737                 Screen.__init__(self, session)
738                 self.session = session
739                 self.skin_path = plugin_path
740                 self.cmdlist = cmdlist
741
742                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
743                 {
744                         "ok": self.process_all,
745                         "back": self.exit,
746                         "red": self.exit,
747                         "green": self.process_extensions,
748                 }, -1)
749
750                 self.list = []
751                 self["list"] = List(self.list)
752                 self["key_red"] = StaticText(_("Cancel"))
753                 self["key_green"] = StaticText(_("Only extensions."))
754                 self["status"] = StaticText(_("Following tasks will be done after you press OK!"))
755
756                 self.onShown.append(self.setWindowTitle)
757                 self.onLayoutFinish.append(self.rebuildList)
758
759         def setWindowTitle(self):
760                 self.setTitle(_("Plugin manager activity information"))
761
762         def rebuildList(self):
763                 self.list = []
764                 if self.cmdlist is not None:
765                         for entry in self.cmdlist:
766                                 action = ""
767                                 info = ""
768                                 cmd = entry[0]
769                                 if cmd == 0:
770                                         action = 'install'
771                                 elif cmd == 2:
772                                         action = 'remove'
773                                 else:
774                                         action = 'upgrade'
775                                 args = entry[1]
776                                 if cmd == 0:
777                                         info = args['package']
778                                 elif cmd == 2:
779                                         info = args['package']
780                                 else:
781                                         info = _("Dreambox software because updates are available.")
782
783                                 self.list.append(self.buildEntryComponent(action,info))
784                         self['list'].setList(self.list)
785                         self['list'].updateList(self.list)
786
787         def buildEntryComponent(self, action,info):
788                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
789                 upgradepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
790                 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
791                 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
792                 if action == 'install':
793                         return(( _('Installing'), info, installpng, divpng))
794                 elif action == 'remove':
795                         return(( _('Removing'), info, removepng, divpng))
796                 else:
797                         return(( _('Upgrading'), info, upgradepng, divpng))
798
799         def exit(self):
800                 self.close()
801
802         def process_all(self):
803                 self.close((True,None))
804
805         def process_extensions(self):
806                 self.list = []
807                 if self.cmdlist is not None:
808                         for entry in self.cmdlist:
809                                 cmd = entry[0]
810                                 if entry[0] in (0,2):
811                                         self.list.append((entry))
812                 self.close((False,self.list))
813
814
815 class PluginManagerHelp(Screen):
816         skin = """
817                 <screen name="PluginManagerHelp" position="center,center" size="560,450" title="Plugin manager help" >
818                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
819                         <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" />
820                         <widget source="list" render="Listbox" position="5,50" size="550,350" scrollbarMode="showOnDemand" selectionDisabled="1">
821                                 <convert type="TemplatedMultiContent">
822                                         {"template": [
823                                                         MultiContentEntryText(pos = (50, 0), size = (150, 26), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
824                                                         MultiContentEntryText(pos = (50, 27), size = (540, 23), font=1, flags = RT_HALIGN_LEFT, text = 1), # index 1 is the state
825                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 1), size = (48, 48), png = 2), # index 2 is the status pixmap
826                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 48), size = (550, 2), png = 3), # index 3 is the div pixmap
827                                                 ],
828                                         "fonts": [gFont("Regular", 24),gFont("Regular", 22)],
829                                         "itemHeight": 50
830                                         }
831                                 </convert>
832                         </widget>
833                         <ePixmap pixmap="skin_default/div-h.png" position="0,404" zPosition="10" size="560,2" transparent="1" alphatest="on" />
834                         <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" />
835                 </screen>"""
836
837         def __init__(self, session, plugin_path):
838                 Screen.__init__(self, session)
839                 self.session = session
840                 self.skin_path = plugin_path
841
842                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
843                 {
844                         "back": self.exit,
845                         "red": self.exit,
846                 }, -1)
847
848                 self.list = []
849                 self["list"] = List(self.list)
850                 self["key_red"] = StaticText(_("Close"))
851                 self["status"] = StaticText(_("A small overview of the available icon states and actions."))
852
853                 self.onShown.append(self.setWindowTitle)
854                 self.onLayoutFinish.append(self.rebuildList)
855
856         def setWindowTitle(self):
857                 self.setTitle(_("Plugin manager help"))
858
859         def rebuildList(self):
860                 self.list = []
861                 self.list.append(self.buildEntryComponent('install'))
862                 self.list.append(self.buildEntryComponent('installable'))
863                 self.list.append(self.buildEntryComponent('installed'))
864                 self.list.append(self.buildEntryComponent('remove'))
865                 self['list'].setList(self.list)
866                 self['list'].updateList(self.list)
867
868         def buildEntryComponent(self, state):
869                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
870                 installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
871                 installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
872                 removepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
873                 installpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/install.png"))
874
875                 if state == 'installed':
876                         return(( _('This plugin is installed.'), _('You can remove this plugin.'), installedpng, divpng))
877                 elif state == 'installable':
878                         return(( _('This plugin is not installed.'), _('You can install this plugin.'), installablepng, divpng))
879                 elif state == 'install':
880                         return(( _('This plugin will be installed.'), _('You can cancel the installation.'), installpng, divpng))
881                 elif state == 'remove':
882                         return(( _('This plugin will be removed.'), _('You can cancel the removal.'), removepng, divpng))
883
884         def exit(self):
885                 self.close()
886
887
888 class PluginDetails(Screen, DreamInfoHandler):
889         skin = """
890                 <screen name="PluginDetails" position="center,center" size="600,440" title="Plugin details" >
891                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
892                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
893                         <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" />
894                         <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" />
895                         <widget source="author" render="Label" position="10,50" size="500,25" zPosition="10" font="Regular;21" transparent="1" />
896                         <widget name="statuspic" position="550,40" size="48,48" alphatest="on"/>
897                         <widget name="divpic" position="0,80" size="600,2" alphatest="on"/>
898                         <widget name="detailtext" position="10,90" size="270,330" zPosition="10" font="Regular;21" transparent="1" halign="left" valign="top"/>
899                         <widget name="screenshot" position="290,90" size="300,330" alphatest="on"/>
900                 </screen>"""
901         def __init__(self, session, plugin_path, packagedata = None):
902                 Screen.__init__(self, session)
903                 self.skin_path = plugin_path
904                 self.language = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
905                 self.attributes = None
906                 self.translatedAttributes = None
907                 DreamInfoHandler.__init__(self, self.statusCallback, blocking = False, language = self.language)
908                 self.directory = resolveFilename(SCOPE_METADIR)
909                 if packagedata:
910                         self.pluginname = packagedata[0]
911                         self.details = packagedata[1]
912                         self.pluginstate = packagedata[4]
913                         self.statuspicinstance = packagedata[5]
914                         self.divpicinstance = packagedata[6]
915                         self.fillPackageDetails(self.details)
916
917                 self.thumbnail = ""
918
919                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
920                 {
921                         "back": self.exit,
922                         "red": self.exit,
923                         "green": self.go,
924                         "up": self.pageUp,
925                         "down": self.pageDown,
926                         "left": self.pageUp,
927                         "right": self.pageDown,
928                 }, -1)
929
930                 self["key_red"] = StaticText(_("Close"))
931                 self["key_green"] = StaticText("")
932                 self["author"] = StaticText()
933                 self["statuspic"] = Pixmap()
934                 self["divpic"] = Pixmap()
935                 self["screenshot"] = Pixmap()
936                 self["detailtext"] = ScrollLabel()
937
938                 self["statuspic"].hide()
939                 self["screenshot"].hide()
940                 self["divpic"].hide()
941
942                 self.package = self.packageDetails[0]
943                 if self.package[0].has_key("attributes"):
944                         self.attributes = self.package[0]["attributes"]
945                 if self.package[0].has_key("translation"):
946                         self.translatedAttributes = self.package[0]["translation"]
947
948                 self.cmdList = []
949                 self.oktext = _("\nAfter pressing OK, please wait!")
950                 self.picload = ePicLoad()
951                 self.picload.PictureData.get().append(self.paintScreenshotPixmapCB)
952                 self.onShown.append(self.setWindowTitle)
953                 self.onLayoutFinish.append(self.setInfos)
954
955         def setWindowTitle(self):
956                 self.setTitle(_("Details for extension: " + self.pluginname))
957
958         def exit(self):
959                 self.close(False)
960
961         def pageUp(self):
962                 self["detailtext"].pageUp()
963
964         def pageDown(self):
965                 self["detailtext"].pageDown()
966
967         def statusCallback(self, status, progress):
968                 pass
969
970         def setInfos(self):
971                 if self.translatedAttributes.has_key("name"):
972                         self.pluginname = self.translatedAttributes["name"]
973                 elif self.attributes.has_key("name"):
974                         self.pluginname = self.attributes["name"]
975                 else:
976                         self.pluginname = _("unknown")
977
978                 if self.translatedAttributes.has_key("author"):
979                         self.author = self.translatedAttributes["author"]
980                 elif self.attributes.has_key("author"):
981                         self.author = self.attributes["author"]
982                 else:
983                         self.author = _("unknown")
984
985                 if self.translatedAttributes.has_key("description"):
986                         self.description = self.translatedAttributes["description"]
987                 elif self.attributes.has_key("description"):
988                         self.description = self.attributes["description"]
989                 else:
990                         self.description = _("No description available.")
991
992                 if self.translatedAttributes.has_key("screenshot"):
993                         self.loadThumbnail(self.translatedAttributes)
994                 else:
995                         self.loadThumbnail(self.attributes)
996
997                 self["author"].setText(_("Author: ") + self.author)
998                 self["detailtext"].setText(self.description.strip())
999                 if self.pluginstate in ('installable', 'install'):
1000                         self["key_green"].setText(_("Install"))
1001                 else:
1002                         self["key_green"].setText(_("Remove"))
1003
1004         def loadThumbnail(self, entry):
1005                 thumbnailUrl = None
1006                 if entry.has_key("screenshot"):
1007                         thumbnailUrl = entry["screenshot"]
1008                 if thumbnailUrl is not None:
1009                         self.thumbnail = "/tmp/" + thumbnailUrl.split('/')[-1]
1010                         print "[PluginDetails] downloading screenshot " + thumbnailUrl + " to " + self.thumbnail
1011                         client.downloadPage(thumbnailUrl,self.thumbnail).addCallback(self.setThumbnail).addErrback(self.fetchFailed)
1012                 else:
1013                         self.setThumbnail(noScreenshot = True)
1014
1015         def setThumbnail(self, noScreenshot = False):
1016                 if not noScreenshot:
1017                         filename = self.thumbnail
1018                 else:
1019                         filename = resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/noprev.png")
1020
1021                 sc = AVSwitch().getFramebufferScale()
1022                 self.picload.setPara((self["screenshot"].instance.size().width(), self["screenshot"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
1023                 self.picload.startDecode(filename)
1024
1025                 if self.statuspicinstance != None:
1026                         self["statuspic"].instance.setPixmap(self.statuspicinstance.__deref__())
1027                         self["statuspic"].show()
1028                 if self.divpicinstance != None:
1029                         self["divpic"].instance.setPixmap(self.divpicinstance.__deref__())
1030                         self["divpic"].show()
1031
1032         def paintScreenshotPixmapCB(self, picInfo=None):
1033                 ptr = self.picload.getData()
1034                 if ptr != None:
1035                         self["screenshot"].instance.setPixmap(ptr.__deref__())
1036                         self["screenshot"].show()
1037                 else:
1038                         self.setThumbnail(noScreenshot = True)
1039
1040         def go(self):
1041                 if self.attributes.has_key("package"):
1042                         self.packagefiles = self.attributes["package"]
1043                 self.cmdList = []
1044                 if self.pluginstate in ('installed', 'remove'):
1045                         if self.packagefiles:
1046                                 for package in self.packagefiles[:]:
1047                                         self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package["name"] }))
1048                                         if len(self.cmdList):
1049                                                 self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + self.pluginname + "\n" + self.oktext)
1050                 else:
1051                         if self.packagefiles:
1052                                 for package in self.packagefiles[:]:
1053                                         self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package["name"] }))
1054                                         if len(self.cmdList):
1055                                                 self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + self.pluginname + "\n" + self.oktext)
1056
1057         def runUpgrade(self, result):
1058                 if result:
1059                         self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
1060
1061         def runUpgradeFinished(self):
1062                 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Installation finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1063
1064         def UpgradeReboot(self, result):
1065                 if result is None:
1066                         return
1067                 if result is False:
1068                         self.close(True)
1069                 if result:
1070                         quitMainloop(3)
1071
1072         def runRemove(self, result):
1073                 if result:
1074                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
1075
1076         def runRemoveFinished(self):
1077                 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1078
1079         def RemoveReboot(self, result):
1080                 if result is None:
1081                         return
1082                 if result is False:
1083                         self.close(True)
1084                 if result:
1085                         quitMainloop(3)
1086
1087         def reloadPluginlist(self):
1088                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1089
1090         def fetchFailed(self,string):
1091                 self.setThumbnail(noScreenshot = True)
1092                 print "[PluginDetails] fetch failed " + string.getErrorMessage()
1093
1094
1095 class UpdatePlugin(Screen):
1096         skin = """
1097                 <screen name="UpdatePlugin" position="center,center" size="550,200" title="Software update" >
1098                         <widget name="activityslider" position="0,0" size="550,5"  />
1099                         <widget name="slider" position="0,150" size="550,30"  />
1100                         <widget source="package" render="Label" position="10,30" size="540,20" font="Regular;18" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1101                         <widget source="status" render="Label" position="10,60" size="540,45" font="Regular;20" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
1102                 </screen>"""
1103
1104         def __init__(self, session, args = None):
1105                 Screen.__init__(self, session)
1106
1107                 self.sliderPackages = { "dreambox-dvb-modules": 1, "enigma2": 2, "tuxbox-image-info": 3 }
1108
1109                 self.slider = Slider(0, 4)
1110                 self["slider"] = self.slider
1111                 self.activityslider = Slider(0, 100)
1112                 self["activityslider"] = self.activityslider
1113                 self.status = StaticText(_("Upgrading Dreambox... Please wait"))
1114                 self["status"] = self.status
1115                 self.package = StaticText()
1116                 self["package"] = self.package
1117
1118                 self.packages = 0
1119                 self.error = 0
1120
1121                 self.activity = 0
1122                 self.activityTimer = eTimer()
1123                 self.activityTimer.callback.append(self.doActivityTimer)
1124                 self.activityTimer.start(100, False)
1125
1126                 self.ipkg = IpkgComponent()
1127                 self.ipkg.addCallback(self.ipkgCallback)
1128
1129                 self.updating = True
1130                 self.package.setText(_("Package list update"))
1131                 self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
1132
1133                 self["actions"] = ActionMap(["WizardActions"], 
1134                 {
1135                         "ok": self.exit,
1136                         "back": self.exit
1137                 }, -1)
1138
1139         def doActivityTimer(self):
1140                 self.activity += 1
1141                 if self.activity == 100:
1142                         self.activity = 0
1143                 self.activityslider.setValue(self.activity)
1144
1145         def ipkgCallback(self, event, param):
1146                 if event == IpkgComponent.EVENT_DOWNLOAD:
1147                         self.status.setText(_("Downloading"))
1148                 elif event == IpkgComponent.EVENT_UPGRADE:
1149                         if self.sliderPackages.has_key(param):
1150                                 self.slider.setValue(self.sliderPackages[param])
1151                         self.package.setText(param)
1152                         self.status.setText(_("Upgrading"))
1153                         self.packages += 1
1154                 elif event == IpkgComponent.EVENT_INSTALL:
1155                         self.package.setText(param)
1156                         self.status.setText(_("Installing"))
1157                         self.packages += 1
1158                 elif event == IpkgComponent.EVENT_CONFIGURING:
1159                         self.package.setText(param)
1160                         self.status.setText(_("Configuring"))
1161                 elif event == IpkgComponent.EVENT_MODIFIED:
1162                         self.session.openWithCallback(
1163                                 self.modificationCallback,
1164                                 MessageBox,
1165                                 _("A configuration file (%s) was modified since Installation.\nDo you want to keep your version?") % (param)
1166                         )
1167                 elif event == IpkgComponent.EVENT_ERROR:
1168                         self.error += 1
1169                 elif event == IpkgComponent.EVENT_DONE:
1170                         if self.updating:
1171                                 self.updating = False
1172                                 self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE, args = {'test_only': False})
1173                         elif self.error == 0:
1174                                 self.slider.setValue(4)
1175                                 
1176                                 self.activityTimer.stop()
1177                                 self.activityslider.setValue(0)
1178                                 
1179                                 self.package.setText("")
1180                                 self.status.setText(_("Done - Installed or upgraded %d packages") % self.packages)
1181                         else:
1182                                 self.activityTimer.stop()
1183                                 self.activityslider.setValue(0)
1184                                 error = _("your dreambox might be unusable now. Please consult the manual for further assistance before rebooting your dreambox.")
1185                                 if self.packages == 0:
1186                                         error = _("No packages were upgraded yet. So you can check your network and try again.")
1187                                 if self.updating:
1188                                         error = _("Your dreambox isn't connected to the internet properly. Please check it and try again.")
1189                                 self.status.setText(_("Error") +  " - " + error)
1190                 #print event, "-", param
1191                 pass
1192
1193         def modificationCallback(self, res):
1194                 self.ipkg.write(res and "N" or "Y")
1195
1196         def exit(self):
1197                 if not self.ipkg.isRunning():
1198                         if self.packages != 0 and self.error == 0:
1199                                 self.session.openWithCallback(self.exitAnswer, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"))
1200                         else:
1201                                 self.close()
1202
1203         def exitAnswer(self, result):
1204                 if result is not None and result:
1205                         quitMainloop(2)
1206                 self.close()
1207
1208
1209
1210 class IPKGMenu(Screen):
1211         skin = """
1212                 <screen name="IPKGMenu" position="center,center" size="560,400" title="Select upgrade source to edit." >
1213                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1214                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1215                         <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" />
1216                         <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" />
1217                         <widget name="filelist" position="5,50" size="550,340" scrollbarMode="showOnDemand" />
1218                 </screen>"""
1219
1220         def __init__(self, session, plugin_path):
1221                 Screen.__init__(self, session)
1222                 self.skin_path = plugin_path
1223                 
1224                 self["key_red"] = StaticText(_("Close"))
1225                 self["key_green"] = StaticText(_("Edit"))
1226
1227                 self.sel = []
1228                 self.val = []
1229                 self.entry = False
1230                 self.exe = False
1231                 
1232                 self.path = ""
1233
1234                 self["actions"] = NumberActionMap(["SetupActions"],
1235                 {
1236                         "ok": self.KeyOk,
1237                         "cancel": self.keyCancel
1238                 }, -1)
1239
1240                 self["shortcuts"] = ActionMap(["ShortcutActions"],
1241                 {
1242                         "red": self.keyCancel,
1243                         "green": self.KeyOk,
1244                 })
1245                 self.flist = []
1246                 self["filelist"] = MenuList(self.flist)
1247                 self.fill_list()
1248                 self.onLayoutFinish.append(self.layoutFinished)
1249
1250         def layoutFinished(self):
1251                 self.setWindowTitle()
1252
1253         def setWindowTitle(self):
1254                 self.setTitle(_("Select upgrade source to edit."))
1255
1256         def fill_list(self):
1257                 self.flist = []
1258                 self.path = '/etc/ipkg/'
1259                 if (os_path.exists(self.path) == False):
1260                         self.entry = False
1261                         return
1262                 for file in listdir(self.path):
1263                         if (file.endswith(".conf")):
1264                                 if file != 'arch.conf':
1265                                         self.flist.append((file))
1266                                         self.entry = True
1267                                         self["filelist"].l.setList(self.flist)
1268
1269         def KeyOk(self):
1270                 if (self.exe == False) and (self.entry == True):
1271                         self.sel = self["filelist"].getCurrent()
1272                         self.val = self.path + self.sel
1273                         self.session.open(IPKGSource, self.val)
1274
1275         def keyCancel(self):
1276                 self.close()
1277
1278         def Exit(self):
1279                 self.close()
1280
1281
1282 class IPKGSource(Screen):
1283         skin = """
1284                 <screen name="IPKGSource" position="center,center" size="560,80" title="Edit upgrade source url." >
1285                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1286                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1287                         <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" />
1288                         <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" />
1289                         <widget name="text" position="5,50" size="550,25" font="Regular;20" backgroundColor="background" foregroundColor="#cccccc" />
1290                 </screen>"""
1291
1292         def __init__(self, session, configfile = None):
1293                 Screen.__init__(self, session)
1294                 self.session = session
1295                 self.configfile = configfile
1296                 text = ""
1297                 if self.configfile:
1298                         try:
1299                                 fp = file(configfile, 'r')
1300                                 sources = fp.readlines()
1301                                 if sources:
1302                                         text = sources[0]
1303                                 fp.close()
1304                         except IOError:
1305                                 pass
1306
1307                 desk = getDesktop(0)
1308                 x= int(desk.size().width())
1309                 y= int(desk.size().height())
1310
1311                 self["key_red"] = StaticText(_("Cancel"))
1312                 self["key_green"] = StaticText(_("Save"))
1313
1314                 if (y>=720):
1315                         self["text"] = Input(text, maxSize=False, type=Input.TEXT)
1316                 else:
1317                         self["text"] = Input(text, maxSize=False, visible_width = 55, type=Input.TEXT)
1318
1319                 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "TextEntryActions", "KeyboardInputActions","ShortcutActions"], 
1320                 {
1321                         "ok": self.go,
1322                         "back": self.close,
1323                         "red": self.close,
1324                         "green": self.go,
1325                         "left": self.keyLeft,
1326                         "right": self.keyRight,
1327                         "home": self.keyHome,
1328                         "end": self.keyEnd,
1329                         "deleteForward": self.keyDeleteForward,
1330                         "deleteBackward": self.keyDeleteBackward,
1331                         "1": self.keyNumberGlobal,
1332                         "2": self.keyNumberGlobal,
1333                         "3": self.keyNumberGlobal,
1334                         "4": self.keyNumberGlobal,
1335                         "5": self.keyNumberGlobal,
1336                         "6": self.keyNumberGlobal,
1337                         "7": self.keyNumberGlobal,
1338                         "8": self.keyNumberGlobal,
1339                         "9": self.keyNumberGlobal,
1340                         "0": self.keyNumberGlobal
1341                 }, -1)
1342
1343                 self.onLayoutFinish.append(self.layoutFinished)
1344
1345         def layoutFinished(self):
1346                 self.setWindowTitle()
1347                 self["text"].right()
1348
1349         def setWindowTitle(self):
1350                 self.setTitle(_("Edit upgrade source url."))
1351
1352         def go(self):
1353                 text = self["text"].getText()
1354                 if text:
1355                         fp = file(self.configfile, 'w')
1356                         fp.write(text)
1357                         fp.write("\n")
1358                         fp.close()
1359                 self.close()
1360
1361         def keyLeft(self):
1362                 self["text"].left()
1363         
1364         def keyRight(self):
1365                 self["text"].right()
1366         
1367         def keyHome(self):
1368                 self["text"].home()
1369         
1370         def keyEnd(self):
1371                 self["text"].end()
1372         
1373         def keyDeleteForward(self):
1374                 self["text"].delete()
1375         
1376         def keyDeleteBackward(self):
1377                 self["text"].deleteBackward()
1378         
1379         def keyNumberGlobal(self, number):
1380                 self["text"].number(number)
1381
1382
1383 class PacketManager(Screen):
1384         skin = """
1385                 <screen name="PacketManager" position="center,center" size="530,420" title="Packet manager" >
1386                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1387                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1388                         <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" />
1389                         <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" />
1390                         <widget source="list" render="Listbox" position="5,50" size="520,365" scrollbarMode="showOnDemand">
1391                                 <convert type="TemplatedMultiContent">
1392                                         {"template": [
1393                                                         MultiContentEntryText(pos = (5, 1), size = (440, 28), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the name
1394                                                         MultiContentEntryText(pos = (5, 26), size = (440, 20), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the description
1395                                                         MultiContentEntryPixmapAlphaTest(pos = (445, 2), size = (48, 48), png = 4), # index 4 is the status pixmap
1396                                                         MultiContentEntryPixmapAlphaTest(pos = (5, 50), size = (510, 2), png = 5), # index 4 is the div pixmap
1397                                                 ],
1398                                         "fonts": [gFont("Regular", 22),gFont("Regular", 14)],
1399                                         "itemHeight": 52
1400                                         }
1401                                 </convert>
1402                         </widget>
1403                 </screen>"""
1404                 
1405         def __init__(self, session, plugin_path, args = None):
1406                 Screen.__init__(self, session)
1407                 self.session = session
1408                 self.skin_path = plugin_path
1409
1410                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"], 
1411                 {
1412                         "ok": self.go,
1413                         "back": self.exit,
1414                         "red": self.exit,
1415                         "green": self.reload,
1416                 }, -1)
1417                 
1418                 self.list = []
1419                 self.statuslist = []
1420                 self["list"] = List(self.list)
1421                 self["key_red"] = StaticText(_("Close"))
1422                 self["key_green"] = StaticText(_("Reload"))
1423
1424                 self.list_updating = True
1425                 self.packetlist = []
1426                 self.installed_packetlist = {}
1427                 self.Console = Console()
1428                 self.cmdList = []
1429                 self.cachelist = []
1430                 self.cache_ttl = 86400  #600 is default, 0 disables, Seconds cache is considered valid (24h should be ok for caching ipkgs)
1431                 self.cache_file = '/usr/lib/enigma2/python/Plugins/SystemPlugins/SoftwareManager/packetmanager.cache' #Path to cache directory   
1432                 self.oktext = _("\nAfter pressing OK, please wait!")
1433                 self.unwanted_extensions = ('-dbg', '-dev', '-doc', 'busybox')
1434
1435                 self.ipkg = IpkgComponent()
1436                 self.ipkg.addCallback(self.ipkgCallback)
1437                 self.onShown.append(self.setWindowTitle)
1438                 self.onLayoutFinish.append(self.rebuildList)
1439
1440         def exit(self):
1441                 self.ipkg.stop()
1442                 if self.Console is not None:
1443                         if len(self.Console.appContainers):
1444                                 for name in self.Console.appContainers.keys():
1445                                         self.Console.kill(name)
1446                 self.close()
1447
1448         def reload(self):
1449                 if (os_path.exists(self.cache_file) == True):
1450                         remove(self.cache_file)
1451                         self.list_updating = True
1452                         self.rebuildList()
1453                         
1454         def setWindowTitle(self):
1455                 self.setTitle(_("Packet manager"))
1456
1457         def setStatus(self,status = None):
1458                 if status:
1459                         self.statuslist = []
1460                         divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1461                         if status == 'update':
1462                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgrade.png"))
1463                                 self.statuslist.append(( _("Package list update"), '', _("Trying to download a new packetlist. Please wait..." ),'',statuspng, divpng ))
1464                                 self['list'].setList(self.statuslist)   
1465                         elif status == 'error':
1466                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/remove.png"))
1467                                 self.statuslist.append(( _("Error"), '', _("There was an error downloading the packetlist. Please try again." ),'',statuspng, divpng ))
1468                                 self['list'].setList(self.statuslist)                           
1469
1470         def rebuildList(self):
1471                 self.setStatus('update')
1472                 self.inv_cache = 0
1473                 self.vc = valid_cache(self.cache_file, self.cache_ttl)
1474                 if self.cache_ttl > 0 and self.vc != 0:
1475                         try:
1476                                 self.buildPacketList()
1477                         except:
1478                                 self.inv_cache = 1
1479                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
1480                         self.run = 0
1481                         self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)
1482
1483         def go(self, returnValue = None):
1484                 cur = self["list"].getCurrent()
1485                 if cur:
1486                         status = cur[3]
1487                         package = cur[0]
1488                         self.cmdList = []
1489                         if status == 'installed':
1490                                 self.cmdList.append((IpkgComponent.CMD_REMOVE, { "package": package }))
1491                                 if len(self.cmdList):
1492                                         self.session.openWithCallback(self.runRemove, MessageBox, _("Do you want to remove the package:\n") + package + "\n" + self.oktext)
1493                         elif status == 'upgradeable':
1494                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
1495                                 if len(self.cmdList):
1496                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to upgrade the package:\n") + package + "\n" + self.oktext)
1497                         elif status == "installable":
1498                                 self.cmdList.append((IpkgComponent.CMD_INSTALL, { "package": package }))
1499                                 if len(self.cmdList):
1500                                         self.session.openWithCallback(self.runUpgrade, MessageBox, _("Do you want to install the package:\n") + package + "\n" + self.oktext)
1501
1502         def runRemove(self, result):
1503                 if result:
1504                         self.session.openWithCallback(self.runRemoveFinished, Ipkg, cmdList = self.cmdList)
1505
1506         def runRemoveFinished(self):
1507                 self.session.openWithCallback(self.RemoveReboot, MessageBox, _("Remove finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1508
1509         def RemoveReboot(self, result):
1510                 if result is None:
1511                         return
1512                 if result is False:
1513                         cur = self["list"].getCurrent()
1514                         if cur:
1515                                 item = self['list'].getIndex()
1516                                 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installable')
1517                                 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installable']
1518                                 self['list'].setList(self.list)
1519                                 write_cache(self.cache_file, self.cachelist)
1520                                 self.reloadPluginlist()
1521                 if result:
1522                         quitMainloop(3)
1523
1524         def runUpgrade(self, result):
1525                 if result:
1526                         self.session.openWithCallback(self.runUpgradeFinished, Ipkg, cmdList = self.cmdList)
1527
1528         def runUpgradeFinished(self):
1529                 self.session.openWithCallback(self.UpgradeReboot, MessageBox, _("Upgrade finished.") +" "+_("Do you want to reboot your Dreambox?"), MessageBox.TYPE_YESNO)
1530                 
1531         def UpgradeReboot(self, result):
1532                 if result is None:
1533                         return
1534                 if result is False:
1535                         cur = self["list"].getCurrent()
1536                         if cur:
1537                                 item = self['list'].getIndex()
1538                                 self.list[item] = self.buildEntryComponent(cur[0], cur[1], cur[2], 'installed')
1539                                 self.cachelist[item] = [cur[0], cur[1], cur[2], 'installed']
1540                                 self['list'].setList(self.list)
1541                                 write_cache(self.cache_file, self.cachelist)
1542                                 self.reloadPluginlist()
1543                 if result:
1544                         quitMainloop(3)
1545
1546         def ipkgCallback(self, event, param):
1547                 if event == IpkgComponent.EVENT_ERROR:
1548                         self.list_updating = False
1549                         self.setStatus('error')
1550                 elif event == IpkgComponent.EVENT_DONE:
1551                         if self.list_updating:
1552                                 self.list_updating = False
1553                                 if not self.Console:
1554                                         self.Console = Console()
1555                                 cmd = "ipkg list"
1556                                 self.Console.ePopen(cmd, self.IpkgList_Finished)
1557                 #print event, "-", param
1558                 pass
1559
1560         def IpkgList_Finished(self, result, retval, extra_args = None):
1561                 if len(result):
1562                         self.packetlist = []
1563                         for x in result.splitlines():
1564                                 split = x.split(' - ')   #self.blacklisted_packages
1565                                 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
1566                                         self.packetlist.append([split[0].strip(), split[1].strip(),split[2].strip()])
1567                 if not self.Console:
1568                         self.Console = Console()
1569                 cmd = "ipkg list_installed"
1570                 self.Console.ePopen(cmd, self.IpkgListInstalled_Finished)
1571
1572         def IpkgListInstalled_Finished(self, result, retval, extra_args = None):
1573                 if len(result):
1574                         self.installed_packetlist = {}
1575                         for x in result.splitlines():
1576                                 split = x.split(' - ')
1577                                 if not any(split[0].strip().endswith(x) for x in self.unwanted_extensions):
1578                                         self.installed_packetlist[split[0].strip()] = split[1].strip()
1579                 self.buildPacketList()
1580
1581         def buildEntryComponent(self, name, version, description, state):
1582                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/div-h.png"))
1583                 if state == 'installed':
1584                         installedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installed.png"))
1585                         return((name, version, description, state, installedpng, divpng))       
1586                 elif state == 'upgradeable':
1587                         upgradeablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/upgradeable.png"))
1588                         return((name, version, description, state, upgradeablepng, divpng))     
1589                 else:
1590                         installablepng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_CURRENT_PLUGIN, "SystemPlugins/SoftwareManager/installable.png"))
1591                         return((name, version, description, state, installablepng, divpng))
1592
1593         def buildPacketList(self):
1594                 self.list = []
1595                 self.cachelist = []
1596
1597                 if self.cache_ttl > 0 and self.vc != 0:
1598                         print 'Loading packagelist cache from ',self.cache_file
1599                         try:
1600                                 self.cachelist = load_cache(self.cache_file)
1601                                 if len(self.cachelist) > 0:
1602                                         for x in self.cachelist:
1603                                                 self.list.append(self.buildEntryComponent(x[0], x[1], x[2], x[3]))
1604                                         self['list'].setList(self.list)
1605                         except:
1606                                 self.inv_cache = 1
1607
1608                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
1609                         print 'rebuilding fresh package list'
1610                         for x in self.packetlist:
1611                                 status = ""
1612                                 if self.installed_packetlist.has_key(x[0].strip()):
1613                                         if self.installed_packetlist[x[0].strip()] == x[1].strip():
1614                                                 status = "installed"
1615                                                 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
1616                                         else:
1617                                                 status = "upgradeable"
1618                                                 self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
1619                                 else:
1620                                         status = "installable"
1621                                         self.list.append(self.buildEntryComponent(x[0].strip(), x[1].strip(), x[2].strip(), status))
1622                                 if not any(x[0].strip().endswith(x) for x in self.unwanted_extensions):
1623                                         self.cachelist.append([x[0].strip(), x[1].strip(), x[2].strip(), status])
1624                         write_cache(self.cache_file, self.cachelist)
1625                         self['list'].setList(self.list)
1626
1627         def reloadPluginlist(self):
1628                 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
1629
1630 class IpkgInstaller(Screen):
1631         skin = """
1632                 <screen name="IpkgInstaller" position="center,center" size="550,450" title="Install extensions" >
1633                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
1634                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
1635                         <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" />
1636                         <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" />
1637                         <widget name="list" position="5,50" size="540,360" />
1638                         <ePixmap pixmap="skin_default/div-h.png" position="0,410" zPosition="10" size="560,2" transparent="1" alphatest="on" />
1639                         <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" />
1640                 </screen>"""
1641         
1642         def __init__(self, session, list):
1643                 Screen.__init__(self, session)
1644
1645                 self.list = SelectionList()
1646                 self["list"] = self.list
1647                 for listindex in range(len(list)):
1648                         self.list.addSelection(list[listindex], list[listindex], listindex, True)
1649
1650                 self["key_red"] = StaticText(_("Close"))
1651                 self["key_green"] = StaticText(_("Install"))
1652                 self["introduction"] = StaticText(_("Press OK to toggle the selection."))
1653                 
1654                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], 
1655                 {
1656                         "ok": self.list.toggleSelection, 
1657                         "cancel": self.close,
1658                         "red": self.close,
1659                         "green": self.install
1660                 }, -1)
1661
1662         def install(self):
1663                 list = self.list.getSelectionsList()
1664                 cmdList = []
1665                 for item in list:
1666                         cmdList.append((IpkgComponent.CMD_INSTALL, { "package": item[1] }))
1667                 self.session.open(Ipkg, cmdList = cmdList)
1668
1669
1670 def filescan_open(list, session, **kwargs):
1671         filelist = [x.path for x in list]
1672         session.open(IpkgInstaller, filelist) # list
1673
1674 def filescan(**kwargs):
1675         from Components.Scanner import Scanner, ScanPath
1676         return \
1677                 Scanner(mimetypes = ["application/x-debian-package"], 
1678                         paths_to_scan = 
1679                                 [
1680                                         ScanPath(path = "ipk", with_subdirs = True), 
1681                                         ScanPath(path = "", with_subdirs = False), 
1682                                 ], 
1683                         name = "Ipkg", 
1684                         description = _("Install extensions."),
1685                         openfnc = filescan_open, )
1686
1687
1688
1689 def UpgradeMain(session, **kwargs):
1690         session.open(UpdatePluginMenu)
1691
1692 def startSetup(menuid):
1693         if menuid != "setup": 
1694                 return [ ]
1695         return [(_("Software management"), UpgradeMain, "software_manager", 50)]
1696
1697 def autostart(reason, **kwargs):
1698         if reason is True:
1699                 iSoftwareTools.startSoftwareTools()
1700
1701 def Plugins(path, **kwargs):
1702         global plugin_path
1703         plugin_path = path
1704         list = [
1705                 PluginDescriptor(where = [PluginDescriptor.WHERE_NETWORKCONFIG_READ], fnc = autostart),
1706                 PluginDescriptor(name=_("Software management"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_MENU, fnc=startSetup), 
1707                 PluginDescriptor(name=_("Ipkg"), where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
1708         ]
1709         if config.usage.setup_level.index >= 2: # expert+
1710                 list.append(PluginDescriptor(name=_("Software management"), description=_("Manage your receiver's software"), where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=UpgradeMain))
1711         return list