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