1 # -*- coding: utf-8 -*-
2 from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
3 from Screens.Screen import Screen
4 from Screens.MessageBox import MessageBox
5 from Screens.ChoiceBox import ChoiceBox
6 from Screens.HelpMenu import HelpableScreen
7 from Screens.TaskView import JobView
8 from Components.About import about
9 from Components.ActionMap import ActionMap
10 from Components.Sources.StaticText import StaticText
11 from Components.Sources.List import List
12 from Components.Label import Label
13 from Components.FileList import FileList
14 from Components.MenuList import MenuList
15 from Components.MultiContent import MultiContentEntryText
16 from Components.ScrollLabel import ScrollLabel
17 from Components.Harddisk import harddiskmanager
18 from Components.Task import Task, Job, job_manager, Condition
19 from Tools.Directories import fileExists
20 from Tools.HardwareInfo import HardwareInfo
21 from Tools.Downloader import downloadWithProgress
22 from enigma import eConsoleAppContainer, gFont, RT_HALIGN_LEFT, RT_HALIGN_CENTER, RT_VALIGN_CENTER, RT_WRAP, eTimer
23 from os import system, path, access, stat, remove, W_OK, R_OK
24 from twisted.web import client
25 from twisted.internet import reactor, defer
26 from twisted.python import failure
29 class ImageDownloadJob(Job):
30 def __init__(self, url, filename, device=None, mountpoint="/"):
31 Job.__init__(self, _("Download .NFI-Files for USB-Flasher"))
33 MountTask(self, device, mountpoint)
34 ImageDownloadTask(self, url, mountpoint+filename)
35 ImageDownloadTask(self, url[:-4]+".nfo", mountpoint+filename[:-4]+".nfo")
37 UmountTask(self, mountpoint)
40 self.tasks[0].args += self.tasks[0].retryargs
43 class MountTask(Task):
44 def __init__(self, job, device, mountpoint):
45 Task.__init__(self, job, ("mount"))
47 self.args += [device, mountpoint, "-orw,sync"]
50 def processOutput(self, data):
51 print "[MountTask] output:", data
53 class UmountTask(Task):
54 def __init__(self, job, mountpoint):
55 Task.__init__(self, job, ("mount"))
56 self.setTool("umount")
57 self.args += [mountpoint]
60 class DownloaderPostcondition(Condition):
61 def check(self, task):
62 return task.returncode == 0
64 def getErrorMessage(self, task):
65 return self.error_message
67 class ImageDownloadTask(Task):
68 def __init__(self, job, url, path):
69 Task.__init__(self, job, _("Downloading"))
70 self.postconditions.append(DownloaderPostcondition())
74 self.error_message = ""
75 self.last_recvbytes = 0
76 self.error_message = None
78 def run(self, callback):
79 self.callback = callback
80 self.download = downloadWithProgress(self.url,self.path)
81 self.download.addProgress(self.download_progress)
82 self.download.start().addCallback(self.download_finished).addErrback(self.download_failed)
83 print "[ImageDownloadTask] downloading", self.url, "to", self.path
85 def download_progress(self, recvbytes, totalbytes):
86 #print "[update_progress] recvbytes=%d, totalbytes=%d" % (recvbytes, totalbytes)
87 if ( recvbytes - self.last_recvbytes ) > 10000: # anti-flicker
88 self.progress = int(100*(float(recvbytes)/float(totalbytes)))
89 self.name = _("Downloading") + ' ' + "%d of %d kBytes" % (recvbytes/1024, totalbytes/1024)
90 self.last_recvbytes = recvbytes
92 def download_failed(self, failure_instance=None, error_message=""):
93 self.error_message = error_message
94 if error_message == "" and failure_instance is not None:
95 self.error_message = failure_instance.getErrorMessage()
96 print "[download_failed]", self.error_message
97 Task.processFinished(self, 1)
99 def download_finished(self, string=""):
100 print "[download_finished]", string
101 Task.processFinished(self, 0)
103 class StickWizardJob(Job):
104 def __init__(self, path):
105 Job.__init__(self, _("USB stick wizard"))
108 while self.device[-1:] == "/" or self.device[-1:].isdigit():
109 self.device = self.device[:-1]
111 box = HardwareInfo().get_device_name()
112 url = "http://www.dreamboxupdate.com/download/opendreambox/dreambox-nfiflasher-%s.tar.bz2" % box
113 self.downloadfilename = "/tmp/dreambox-nfiflasher-%s.tar.bz2" % box
114 self.imagefilename = "/tmp/nfiflash_%s.img" % box
115 #UmountTask(self, device)
117 ImageDownloadTask(self, url, self.downloadfilename)
121 class PartitionTaskPostcondition(Condition):
122 def check(self, task):
123 return task.returncode == 0
125 def getErrorMessage(self, task):
127 task.ERROR_BLKRRPART: ("Device or resource busy"),
128 task.ERROR_UNKNOWN: (task.errormsg)
131 class PartitionTask(Task):
132 ERROR_UNKNOWN, ERROR_BLKRRPART = range(2)
133 def __init__(self, job):
134 Task.__init__(self, job, ("partitioning"))
135 self.postconditions.append(PartitionTaskPostcondition())
137 self.setTool("sfdisk")
138 self.args += [self.job.device]
140 self.initial_input = "0 - 0x6 *\n;\n;\n;\ny"
143 def run(self, callback):
144 Task.run(self, callback)
146 def processOutput(self, data):
147 print "[PartitionTask] output:", data
148 if data.startswith("BLKRRPART:"):
149 self.error = self.ERROR_BLKRRPART
151 self.error = self.ERROR_UNKNOWN
154 class UnpackTask(Task):
155 def __init__(self, job):
156 Task.__init__(self, job, ("Unpacking USB flasher image..."))
159 self.args += ["-xjvf", self.job.downloadfilename]
162 self.delayTimer = eTimer()
163 self.delayTimer.callback.append(self.progress_increment)
165 def run(self, callback):
166 Task.run(self, callback)
167 self.delayTimer.start(1000, False)
169 def progress_increment(self):
172 def processOutput(self, data):
173 print "[UnpackTask] output: \'%s\'" % data
174 self.job.imagefilename = data
177 self.delayTimer.callback.remove(self.progress_increment)
179 class CopyTask(Task):
180 def __init__(self, job):
181 Task.__init__(self, job, ("Copying USB flasher boot image to stick..."))
184 self.args += ["if=%s" % self.job.imagefilename, "of=%s1" % self.job.device]
187 self.delayTimer = eTimer()
188 self.delayTimer.callback.append(self.progress_increment)
190 def run(self, callback):
191 Task.run(self, callback)
192 self.delayTimer.start(100, False)
194 def progress_increment(self):
197 def processOutput(self, data):
198 print "[CopyTask] output:", data
201 self.delayTimer.callback.remove(self.progress_increment)
203 class NFOViewer(Screen):
205 <screen name="NFOViewer" position="center,center" size="610,410" title="Changelog viewer" >
206 <widget name="changelog" position="10,10" size="590,380" font="Regular;16" />
209 def __init__(self, session, nfo):
210 Screen.__init__(self, session)
211 self["changelog"] = ScrollLabel(nfo)
213 self["ViewerActions"] = ActionMap(["SetupActions", "ColorActions", "DirectionActions"],
219 "down": self.pageDown,
223 self["changelog"].pageUp()
226 self["changelog"].pageDown()
231 class feedDownloader:
232 def __init__(self, feed_base, box, OE_vers):
233 print "[feedDownloader::init] feed_base=%s, box=%s" % (feed_base, box)
234 self.feed_base = feed_base
235 self.OE_vers = OE_vers
238 def getList(self, callback, errback):
239 self.urlbase = "%s/%s/%s/images/" % (self.feed_base, self.OE_vers, self.box)
240 print "[getList]", self.urlbase
241 self.callback = callback
242 self.errback = errback
243 client.getPage(self.urlbase).addCallback(self.feed_finished).addErrback(self.feed_failed)
245 def feed_failed(self, failure_instance):
246 print "[feed_failed]", str(failure_instance)
247 self.errback(failure_instance.getErrorMessage())
249 def feed_finished(self, feedhtml):
250 print "[feed_finished]"
251 fileresultmask = re.compile("<a class=[\'\"]nfi[\'\"] href=[\'\"](?P<url>.*?)[\'\"]>(?P<name>.*?.nfi)</a>", re.DOTALL)
252 searchresults = fileresultmask.finditer(feedhtml)
255 for x in searchresults:
257 if url[0:7] != "http://":
258 url = self.urlbase + x.group("url")
259 name = x.group("name")
261 fileresultlist.append(entry)
262 self.callback(fileresultlist, self.OE_vers)
264 class DeviceBrowser(Screen, HelpableScreen):
266 <screen name="DeviceBrowser" position="center,center" size="520,430" title="Please select target medium" >
267 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
268 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
269 <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" />
270 <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" />
271 <widget source="message" render="Label" position="5,50" size="510,150" font="Regular;16" />
272 <widget name="filelist" position="5,210" size="510,220" scrollbarMode="showOnDemand" />
275 def __init__(self, session, startdir, message="", showDirectories = True, showFiles = True, showMountpoints = True, matchingPattern = "", useServiceRef = False, inhibitDirs = False, inhibitMounts = False, isTop = False, enableWrapAround = False, additionalExtensions = None):
276 Screen.__init__(self, session)
278 HelpableScreen.__init__(self)
280 self["key_red"] = StaticText(_("Cancel"))
281 self["key_green"] = StaticText()
282 self["message"] = StaticText(message)
284 self.filelist = FileList(startdir, showDirectories = showDirectories, showFiles = showFiles, showMountpoints = showMountpoints, matchingPattern = matchingPattern, useServiceRef = useServiceRef, inhibitDirs = inhibitDirs, inhibitMounts = inhibitMounts, isTop = isTop, enableWrapAround = enableWrapAround, additionalExtensions = additionalExtensions)
285 self["filelist"] = self.filelist
287 self["FilelistActions"] = ActionMap(["SetupActions", "ColorActions"],
295 hotplugNotifier.append(self.hotplugCB)
296 self.onShown.append(self.updateButton)
297 self.onClose.append(self.removeHotplug)
299 def hotplugCB(self, dev, action):
300 print "[hotplugCB]", dev, action
303 def updateButton(self):
305 if self["filelist"].getFilename() or self["filelist"].getCurrentDirectory():
306 self["key_green"].text = _("Use")
308 self["key_green"].text = ""
310 def removeHotplug(self):
311 print "[removeHotplug]"
312 hotplugNotifier.remove(self.hotplugCB)
315 if self.filelist.canDescent():
316 if self["filelist"].showMountpoints == True and self["filelist"].showDirectories == False:
319 self.filelist.descent()
322 print "[use]", self["filelist"].getCurrentDirectory(), self["filelist"].getFilename()
323 if self["filelist"].getCurrentDirectory() is not None:
324 if self.filelist.canDescent() and self["filelist"].getFilename() and len(self["filelist"].getFilename()) > len(self["filelist"].getCurrentDirectory()):
325 self.filelist.descent()
326 self.close(self["filelist"].getCurrentDirectory())
327 elif self["filelist"].getFilename():
328 self.close(self["filelist"].getFilename())
333 (ALLIMAGES, RELEASE, EXPERIMENTAL, STICK_WIZARD, START) = range(5)
335 class NFIDownload(Screen):
337 <screen name="NFIDownload" position="center,center" size="610,410" title="NFIDownload" >
338 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
339 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
340 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
341 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
342 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#9f1313" transparent="1" />
343 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
344 <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#a08500" transparent="1" />
345 <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#18188b" transparent="1" />
346 <ePixmap pixmap="skin_default/border_menu_350.png" position="5,50" zPosition="1" size="350,300" transparent="1" alphatest="on" />
347 <widget source="menu" render="Listbox" position="15,60" size="330,290" scrollbarMode="showOnDemand">
348 <convert type="TemplatedMultiContent">
351 MultiContentEntryText(pos = (2, 2), size = (330, 24), flags = RT_HALIGN_LEFT, text = 1), # index 0 is the MenuText,
352 ], True, "showOnDemand")
354 "fonts": [gFont("Regular", 22)],
359 <widget source="menu" render="Listbox" position="360,50" size="240,300" scrollbarMode="showNever" selectionDisabled="1">
360 <convert type="TemplatedMultiContent">
363 MultiContentEntryText(pos = (2, 2), size = (240, 300), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, text = 2), # index 2 is the Description,
364 ], False, "showNever")
366 "fonts": [gFont("Regular", 22)],
371 <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" />
374 def __init__(self, session, destdir=None):
375 Screen.__init__(self, session)
376 #self.skin_path = plugin_path
379 self.box = HardwareInfo().get_device_name()
380 self.feed_base = "http://www.dreamboxupdate.com/opendreambox" #/1.5/%s/images/" % self.box
381 self.usbmountpoint = "/mnt/usb/"
385 self["menu"] = List(self.menulist)
386 self["key_red"] = StaticText(_("Close"))
387 self["key_green"] = StaticText()
388 self["key_yellow"] = StaticText()
389 self["key_blue"] = StaticText()
391 self["status"] = StaticText(_("Please wait... Loading list..."))
393 self["shortcuts"] = ActionMap(["OkCancelActions", "ColorActions", "ShortcutActions", "DirectionActions"],
398 "blue": self.keyBlue,
400 "upRepeated": self.keyUp,
401 "downRepeated": self.keyDown,
402 "down": self.keyDown,
403 "cancel": self.close,
405 self.onShown.append(self.go)
406 self.feedlists = [[],[],[]]
408 self.container = eConsoleAppContainer()
409 self.container.dataAvail.append(self.tool_avail)
412 self.nfofilename = ""
414 self.target_dir = None
416 def tool_avail(self, string):
417 print "[tool_avail]" + string
418 self.taskstring += string
421 self.onShown.remove(self.go)
422 self["menu"].index = 0
423 url = "http://www.dreamboxupdate.com/download/opendreambox/dreambox-nfiflasher-%s-md5sums" % self.box
424 client.getPage(url).addCallback(self.md5sums_finished).addErrback(self.feed_failed)
426 def md5sums_finished(self, data):
427 print "[md5sums_finished]", data
428 self.stickimage_md5 = data
432 if self.branch == START:
436 self["menu"].setList(self.menulist)
437 #elif self.branch == ALLIMAGES or self.branch == STICK_WIZARD:
441 self.session.open(NFOViewer, self.nfo)
444 print "[keyOk]", self["menu"].getCurrent()
445 current = self["menu"].getCurrent()
447 if self.branch == START:
448 currentEntry = current[0]
449 if currentEntry == RELEASE:
451 self.branch = RELEASE
452 self.askDestination()
453 elif currentEntry == EXPERIMENTAL:
455 self.branch = EXPERIMENTAL
456 self.askDestination()
457 elif currentEntry == ALLIMAGES:
458 self.branch = ALLIMAGES
460 elif currentEntry == STICK_WIZARD:
461 self.askStartWizard()
462 elif self.branch == ALLIMAGES:
463 self.image_idx = self["menu"].getIndex()
464 self.askDestination()
468 self["menu"].selectPrevious()
472 self["menu"].selectNext()
475 def updateButtons(self):
476 current = self["menu"].getCurrent()
478 if self.branch == START:
479 self["key_red"].text = _("Close")
480 currentEntry = current[0]
481 if currentEntry in (RELEASE, EXPERIMENTAL):
482 self.nfo_download(currentEntry, 0)
483 self["key_green"].text = _("Download")
485 self.nfofilename = ""
487 self["key_blue"].text = ""
488 self["key_green"].text = _("continue")
490 elif self.branch == ALLIMAGES:
491 self["key_red"].text = _("Back")
492 self["key_green"].text = _("Download")
493 self.nfo_download(ALLIMAGES, self["menu"].getIndex())
495 def listImages(self):
498 for name, url in self.feedlists[ALLIMAGES]:
499 imagelist.append((url, name, _("Download %s from Server" ) % url, None))
500 self["menu"].setList(imagelist)
502 def getUSBPartitions(self):
503 allpartitions = [ (r.description, r.mountpoint) for r in harddiskmanager.getMountedPartitions(onlyhotplug = True)]
504 print "[getUSBPartitions]", allpartitions
506 for x in allpartitions:
507 print x, x[1] == '/', x[0].find("USB"), access(x[1], R_OK)
508 if x[1] != '/' and x[0].find("USB") > -1: # and access(x[1], R_OK) is True:
509 usbpartition.append(x)
512 def askDestination(self):
513 usbpartition = self.getUSBPartitions()
514 if len(usbpartition) == 1:
515 self.target_dir = usbpartition[0][1]
516 self.ackDestinationDevice(device_description=usbpartition[0][0])
518 self.session.openWithCallback(self.DeviceBrowserClosed, DeviceBrowser, None, showDirectories=True, showMountpoints=True, inhibitMounts=["/autofs/sr0/"])
520 def DeviceBrowserClosed(self, path):
521 print "[DeviceBrowserClosed]", str(path)
522 self.target_dir = path
524 self.ackDestinationDevice()
528 def ackDestinationDevice(self, device_description=None):
529 if device_description == None:
530 dev = self.target_dir
532 dev = device_description
533 message = _("Do you want to download the image to %s ?") % (dev)
534 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.askDestination), (_("Cancel"),self.keyRed)]
535 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
537 def ackDestination_query(self, choice):
538 print "[ackDestination_query]", choice
539 if isinstance(choice, tuple):
544 def ackedDestination(self):
545 print "[ackedDestination]", self.branch, self.target_dir, self.target_dir[8:]
546 self.container.setCWD("/mnt")
547 if self.target_dir[:8] == "/autofs/":
548 self.target_dir = "/dev/" + self.target_dir[8:-1]
550 if self.branch == STICK_WIZARD:
551 job = StickWizardJob(self.target_dir)
552 job_manager.AddJob(job)
553 self.session.openWithCallback(self.StickWizardCB, JobView, job)
555 elif self.branch != STICK_WIZARD:
556 url = self.feedlists[self.branch][self.image_idx][1]
557 filename = self.feedlists[self.branch][self.image_idx][0]
558 print "[getImage] start downloading %s to %s" % (url, path)
559 job = ImageDownloadJob(url, filename, self.target_dir, self.usbmountpoint)
560 job_manager.AddJob(job)
561 self.session.openWithCallback(self.ImageDownloadCB, JobView, job)
563 def StickWizardCB(self, ret=None):
564 self.session.open(MessageBox, _("The USB stick was prepared to be bootable.\nNow you can download an NFI image file!"), type = MessageBox.TYPE_INFO)
565 print "[StickWizardCB]", ret
566 if len(self.feedlists[ALLIMAGES]) == 0:
571 def ImageDownloadCB(self, ret):
572 print "[ImageDownloadCB]", ret
573 self.session.open(MessageBox, _("To update your Dreambox firmware, please follow these steps:\n1) Turn off your box with the rear power switch and plug in the bootable USB stick.\n2) Turn mains back on and hold the DOWN button on the front panel pressed for 10 seconds.\n3) Wait for bootup and follow instructions of the wizard."), type = MessageBox.TYPE_INFO)
576 self.feedDownloader15 = feedDownloader(self.feed_base, self.box, OE_vers="1.5")
577 self.feedDownloader16 = feedDownloader(self.feed_base, self.box, OE_vers="1.6")
578 self.feedlists = [[],[],[]]
579 self.feedDownloader15.getList(self.gotFeed, self.feed_failed)
580 self.feedDownloader16.getList(self.gotFeed, self.feed_failed)
582 def feed_failed(self, message=""):
583 self["status"].text = _("Could not connect to Dreambox .NFI Image Feed Server:") + "\n" + str(message) + "\n" + _("Please check your network settings!")
585 def gotFeed(self, feedlist, OE_vers):
586 print "[gotFeed]", OE_vers
588 experimentallist = []
590 for name, url in feedlist:
591 if name.find("release") > -1:
592 releaselist.append((name, url))
593 if name.find("experimental") > -1:
594 experimentallist.append((name, url))
595 self.feedlists[ALLIMAGES].append((name, url))
598 self.feedlists[RELEASE] = releaselist + self.feedlists[RELEASE]
599 self.feedlists[EXPERIMENTAL] = experimentallist + self.feedlists[RELEASE]
600 elif OE_vers == "1.5":
601 self.feedlists[RELEASE] = self.feedlists[RELEASE] + releaselist
602 self.feedlists[EXPERIMENTAL] = self.feedlists[EXPERIMENTAL] + experimentallist
606 def checkUSBStick(self):
607 self.target_dir = None
608 allpartitions = [ (r.description, r.mountpoint) for r in harddiskmanager.getMountedPartitions(onlyhotplug = True)]
609 print "[checkUSBStick] found partitions:", allpartitions
611 for x in allpartitions:
612 print x, x[1] == '/', x[0].find("USB"), access(x[1], R_OK)
613 if x[1] != '/' and x[0].find("USB") > -1: # and access(x[1], R_OK) is True:
614 usbpartition.append(x)
617 if len(usbpartition) == 1:
618 self.target_dir = usbpartition[0][1]
619 self.md5_passback = self.getFeed
620 self.md5_failback = self.askStartWizard
621 self.md5verify(self.stickimage_md5, self.target_dir)
622 elif usbpartition == []:
623 print "[NFIFlash] needs to create usb flasher stick first!"
624 self.askStartWizard()
626 self.askStartWizard()
628 def askStartWizard(self):
629 self.branch = STICK_WIZARD
630 message = _("""This plugin creates a USB stick which can be used to update the firmware of your Dreambox in case it has no network connection or only WLAN access.
631 First, you need to prepare a USB stick so that it is bootable.
632 In the next step, an NFI image file can be downloaded from the update server and saved on the USB stick.
633 If you already have a prepared bootable USB stick, please insert it now. Otherwise plug in a USB stick with a minimum size of 64 MB!""")
634 self.session.openWithCallback(self.wizardDeviceBrowserClosed, DeviceBrowser, None, message, showDirectories=True, showMountpoints=True, inhibitMounts=["/","/autofs/sr0/","/autofs/sda1/","/media/hdd/","/media/net/","/media/usb/","/media/dvd/"])
636 def wizardDeviceBrowserClosed(self, path):
637 print "[wizardDeviceBrowserClosed]", path
638 self.target_dir = path
640 self.md5_passback = self.getFeed
641 self.md5_failback = self.wizardQuery
642 self.md5verify(self.stickimage_md5, self.target_dir)
646 def wizardQuery(self):
647 print "[wizardQuery]"
648 description = self.target_dir
649 for name, dev in self.getUSBPartitions():
650 if dev == self.target_dir:
652 message = _("You have chosen to create a new .NFI flasher bootable USB stick. This will repartition the USB stick and therefore all data on it will be erased.") + "\n"
653 message += _("The following device was found:\n\n%s\n\nDo you want to write the USB flasher to this stick?") % description
654 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.askStartWizard), (_("Cancel"),self.close)]
655 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
660 latest_release = "Release %s (Opendreambox 1.5)" % self.feedlists[RELEASE][0][0][-9:-4]
661 self.menulist.append((RELEASE, _("Get latest release image"), _("Download %s from Server" ) % latest_release, None))
666 dat = self.feedlists[EXPERIMENTAL][0][0][-12:-4]
667 latest_experimental = "Experimental %s-%s-%s (Opendreambox 1.6)" % (dat[:4], dat[4:6], dat[6:])
668 self.menulist.append((EXPERIMENTAL, _("Get latest experimental image"), _("Download %s from Server") % latest_experimental, None))
672 self.menulist.append((ALLIMAGES, _("Choose image to download"), _("Select desired image from feed list" ), None))
673 self.menulist.append((STICK_WIZARD, _("USB stick wizard"), _("Prepare another USB stick for image flashing" ), None))
674 self["menu"].setList(self.menulist)
675 self["status"].text = _("Currently installed image") + ": %s" % (about.getImageVersionString())
679 def nfo_download(self, branch, idx):
680 nfourl = (self.feedlists[branch][idx][1])[:-4]+".nfo"
681 self.nfofilename = (self.feedlists[branch][idx][0])[:-4]+".nfo"
682 print "[check_for_NFO]", nfourl
683 client.getPage(nfourl).addCallback(self.nfo_finished).addErrback(self.nfo_failed)
685 def nfo_failed(self, failure_instance):
686 print "[nfo_failed] " + str(failure_instance)
687 self["key_blue"].text = ""
688 self.nfofilename = ""
691 def nfo_finished(self,nfodata=""):
692 print "[nfo_finished] " + str(nfodata)
693 self["key_blue"].text = _("Changelog viewer")
696 def md5verify(self, md5, path):
698 print "[verify_md5]", md5, path, cmd
699 self.container.setCWD(path)
700 self.container.appClosed.append(self.md5finished)
701 self.container.execute(cmd)
702 self.container.write(md5)
703 self.container.dataSent.append(self.md5ready)
705 def md5ready(self, retval):
706 self.container.sendEOF()
708 def md5finished(self, retval):
709 print "[md5finished]", str(retval)
710 self.container.appClosed.remove(self.md5finished)
711 self.container.dataSent.remove(self.md5ready)
713 print "check passed! calling", repr(self.md5_passback)
716 print "check failed! calling", repr(self.md5_failback)
719 def main(session, **kwargs):
720 session.open(NFIDownload,"/home/root")
722 def filescan_open(list, session, **kwargs):
723 dev = "/dev/" + (list[0].path).rsplit('/',1)[0][7:]
724 print "mounting device " + dev + " to /mnt/usb..."
725 system("mount "+dev+" /mnt/usb/ -o rw,sync")
726 session.open(NFIDownload,"/mnt/usb/")
728 def filescan(**kwargs):
729 from Components.Scanner import Scanner, ScanPath
731 Scanner(mimetypes = ["application/x-dream-image"],
734 ScanPath(path = "", with_subdirs = False),
737 description = (_("Download .NFI-Files for USB-Flasher")+"..."),
738 openfnc = filescan_open, )