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.openDeviceBrowser()
520 def openDeviceBrowser(self):
521 if self.branch != STICK_WIZARD:
522 self.session.openWithCallback(self.DeviceBrowserClosed, DeviceBrowser, None, showDirectories=True, showMountpoints=True, inhibitMounts=["/autofs/sr0/"])
523 if self.branch == STICK_WIZARD:
524 self.session.openWithCallback(self.DeviceBrowserClosed, DeviceBrowser, None, showDirectories=False, showMountpoints=True, inhibitMounts=["/","/autofs/sr0/"])
526 def DeviceBrowserClosed(self, path):
527 print "[DeviceBrowserClosed]", str(path)
528 self.target_dir = path
530 self.ackDestinationDevice()
534 def ackDestinationDevice(self, device_description=None):
535 if device_description == None:
536 dev = self.target_dir
538 dev = device_description
539 message = _("Do you want to download the image to %s ?") % (dev)
540 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.openDeviceBrowser), (_("Cancel"),self.keyRed)]
541 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
543 def ackDestination_query(self, choice):
544 print "[ackDestination_query]", choice
545 if isinstance(choice, tuple):
550 def ackedDestination(self):
551 print "[ackedDestination]", self.branch, self.target_dir, self.target_dir[8:]
552 self.container.setCWD("/mnt")
553 if self.target_dir[:8] == "/autofs/":
554 self.target_dir = "/dev/" + self.target_dir[8:-1]
556 if self.branch == STICK_WIZARD:
557 job = StickWizardJob(self.target_dir)
558 job_manager.AddJob(job)
559 self.session.openWithCallback(self.StickWizardCB, JobView, job)
561 elif self.branch != STICK_WIZARD:
562 url = self.feedlists[self.branch][self.image_idx][1]
563 filename = self.feedlists[self.branch][self.image_idx][0]
564 print "[getImage] start downloading %s to %s" % (url, path)
565 job = ImageDownloadJob(url, filename, self.target_dir, self.usbmountpoint)
566 job_manager.AddJob(job)
567 self.session.openWithCallback(self.ImageDownloadCB, JobView, job)
569 def StickWizardCB(self, ret=None):
570 self.session.open(MessageBox, _("The USB stick was prepared to be bootable.\nNow you can download an NFI image file!"), type = MessageBox.TYPE_INFO)
571 print "[StickWizardCB]", ret
572 if len(self.feedlists[ALLIMAGES]) == 0:
577 def ImageDownloadCB(self, ret):
578 print "[ImageDownloadCB]", ret
579 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)
582 self.feedDownloader15 = feedDownloader(self.feed_base, self.box, OE_vers="1.5")
583 self.feedDownloader16 = feedDownloader(self.feed_base, self.box, OE_vers="1.6")
584 self.feedlists = [[],[],[]]
585 self.feedDownloader15.getList(self.gotFeed, self.feed_failed)
586 self.feedDownloader16.getList(self.gotFeed, self.feed_failed)
588 def feed_failed(self, message=""):
589 self["status"].text = _("Could not connect to Dreambox .NFI Image Feed Server:") + "\n" + str(message) + "\n" + _("Please check your network settings!")
591 def gotFeed(self, feedlist, OE_vers):
592 print "[gotFeed]", OE_vers
594 experimentallist = []
596 for name, url in feedlist:
597 if name.find("release") > -1:
598 releaselist.append((name, url))
599 if name.find("experimental") > -1:
600 experimentallist.append((name, url))
601 self.feedlists[ALLIMAGES].append((name, url))
604 self.feedlists[RELEASE] = releaselist + self.feedlists[RELEASE]
605 self.feedlists[EXPERIMENTAL] = experimentallist + self.feedlists[RELEASE]
606 elif OE_vers == "1.5":
607 self.feedlists[RELEASE] = self.feedlists[RELEASE] + releaselist
608 self.feedlists[EXPERIMENTAL] = self.feedlists[EXPERIMENTAL] + experimentallist
612 def checkUSBStick(self):
613 self.target_dir = None
614 allpartitions = [ (r.description, r.mountpoint) for r in harddiskmanager.getMountedPartitions(onlyhotplug = True)]
615 print "[checkUSBStick] found partitions:", allpartitions
617 for x in allpartitions:
618 print x, x[1] == '/', x[0].find("USB"), access(x[1], R_OK)
619 if x[1] != '/' and x[0].find("USB") > -1: # and access(x[1], R_OK) is True:
620 usbpartition.append(x)
623 if len(usbpartition) == 1:
624 self.target_dir = usbpartition[0][1]
625 self.md5_passback = self.getFeed
626 self.md5_failback = self.askStartWizard
627 self.md5verify(self.stickimage_md5, self.target_dir)
628 elif usbpartition == []:
629 print "[NFIFlash] needs to create usb flasher stick first!"
630 self.askStartWizard()
632 self.askStartWizard()
634 def askStartWizard(self):
635 self.branch = STICK_WIZARD
636 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.
637 First, you need to prepare a USB stick so that it is bootable.
638 In the next step, an NFI image file can be downloaded from the update server and saved on the USB stick.
639 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!""")
640 self.session.openWithCallback(self.wizardDeviceBrowserClosed, DeviceBrowser, None, message, showDirectories=True, showMountpoints=True, inhibitMounts=["/","/autofs/sr0/"])
642 def wizardDeviceBrowserClosed(self, path):
643 print "[wizardDeviceBrowserClosed]", path
644 self.target_dir = path
646 self.md5_passback = self.getFeed
647 self.md5_failback = self.wizardQuery
648 self.md5verify(self.stickimage_md5, self.target_dir)
652 def wizardQuery(self):
653 print "[wizardQuery]"
654 description = self.target_dir
655 for name, dev in self.getUSBPartitions():
656 if dev == self.target_dir:
658 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"
659 message += _("The following device was found:\n\n%s\n\nDo you want to write the USB flasher to this stick?") % description
660 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.askStartWizard), (_("Cancel"),self.close)]
661 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
666 latest_release = "Release %s (Opendreambox 1.5)" % self.feedlists[RELEASE][0][0][-9:-4]
667 self.menulist.append((RELEASE, _("Get latest release image"), _("Download %s from Server" ) % latest_release, None))
672 dat = self.feedlists[EXPERIMENTAL][0][0][-12:-4]
673 latest_experimental = "Experimental %s-%s-%s (Opendreambox 1.6)" % (dat[:4], dat[4:6], dat[6:])
674 self.menulist.append((EXPERIMENTAL, _("Get latest experimental image"), _("Download %s from Server") % latest_experimental, None))
678 self.menulist.append((ALLIMAGES, _("Choose image to download"), _("Select desired image from feed list" ), None))
679 self.menulist.append((STICK_WIZARD, _("USB stick wizard"), _("Prepare another USB stick for image flashing" ), None))
680 self["menu"].setList(self.menulist)
681 self["status"].text = _("Currently installed image") + ": %s" % (about.getImageVersionString()))
685 def nfo_download(self, branch, idx):
686 nfourl = (self.feedlists[branch][idx][1])[:-4]+".nfo"
687 self.nfofilename = (self.feedlists[branch][idx][0])[:-4]+".nfo"
688 print "[check_for_NFO]", nfourl
689 client.getPage(nfourl).addCallback(self.nfo_finished).addErrback(self.nfo_failed)
691 def nfo_failed(self, failure_instance):
692 print "[nfo_failed] " + str(failure_instance)
693 self["key_blue"].text = ""
694 self.nfofilename = ""
697 def nfo_finished(self,nfodata=""):
698 print "[nfo_finished] " + str(nfodata)
699 self["key_blue"].text = _("Changelog viewer")
702 def md5verify(self, md5, path):
704 print "[verify_md5]", md5, path, cmd
705 self.container.setCWD(path)
706 self.container.appClosed.append(self.md5finished)
707 self.container.execute(cmd)
708 self.container.write(md5)
709 self.container.dataSent.append(self.md5ready)
711 def md5ready(self, retval):
712 self.container.sendEOF()
714 def md5finished(self, retval):
715 print "[md5finished]", str(retval)
716 self.container.appClosed.remove(self.md5finished)
717 self.container.dataSent.remove(self.md5ready)
719 print "check passed! calling", repr(self.md5_passback)
722 print "check failed! calling", repr(self.md5_failback)
725 def main(session, **kwargs):
726 session.open(NFIDownload,"/home/root")
728 def filescan_open(list, session, **kwargs):
729 dev = "/dev/" + (list[0].path).rsplit('/',1)[0][7:]
730 print "mounting device " + dev + " to /mnt/usb..."
731 system("mount "+dev+" /mnt/usb/ -o rw,sync")
732 session.open(NFIDownload,"/mnt/usb/")
734 def filescan(**kwargs):
735 from Components.Scanner import Scanner, ScanPath
737 Scanner(mimetypes = ["application/x-dream-image"],
740 ScanPath(path = "", with_subdirs = False),
743 description = (_("Download .NFI-Files for USB-Flasher")+"..."),
744 openfnc = filescan_open, )