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, isMount
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 if isMount(mountpoint):
34 UmountTask(self, mountpoint)
35 MountTask(self, device, mountpoint)
36 ImageDownloadTask(self, url, mountpoint+filename)
37 ImageDownloadTask(self, url[:-4]+".nfo", mountpoint+filename[:-4]+".nfo")
39 UmountTask(self, mountpoint)
42 self.tasks[0].args += self.tasks[0].retryargs
45 class MountTask(Task):
46 def __init__(self, job, device, mountpoint):
47 Task.__init__(self, job, ("mount"))
50 self.mountpoint = mountpoint
51 self.args += [ device, mountpoint, "-o"+options ]
54 def processOutput(self, data):
55 print "[MountTask] output:", data
57 class UmountTask(Task):
58 def __init__(self, job, mountpoint):
59 Task.__init__(self, job, ("mount"))
60 self.setTool("umount")
61 self.args += [mountpoint]
64 class DownloaderPostcondition(Condition):
65 def check(self, task):
66 return task.returncode == 0
68 def getErrorMessage(self, task):
69 return self.error_message
71 class ImageDownloadTask(Task):
72 def __init__(self, job, url, path):
73 Task.__init__(self, job, _("Downloading"))
74 self.postconditions.append(DownloaderPostcondition())
78 self.error_message = ""
79 self.last_recvbytes = 0
80 self.error_message = None
82 def run(self, callback):
83 self.callback = callback
84 self.download = downloadWithProgress(self.url,self.path)
85 self.download.addProgress(self.download_progress)
86 self.download.start().addCallback(self.download_finished).addErrback(self.download_failed)
87 print "[ImageDownloadTask] downloading", self.url, "to", self.path
89 def download_progress(self, recvbytes, totalbytes):
90 #print "[update_progress] recvbytes=%d, totalbytes=%d" % (recvbytes, totalbytes)
91 if ( recvbytes - self.last_recvbytes ) > 10000: # anti-flicker
92 self.progress = int(100*(float(recvbytes)/float(totalbytes)))
93 self.name = _("Downloading") + ' ' + "%d of %d kBytes" % (recvbytes/1024, totalbytes/1024)
94 self.last_recvbytes = recvbytes
96 def download_failed(self, failure_instance=None, error_message=""):
97 self.error_message = error_message
98 if error_message == "" and failure_instance is not None:
99 self.error_message = failure_instance.getErrorMessage()
100 print "[download_failed]", self.error_message
101 Task.processFinished(self, 1)
103 def download_finished(self, string=""):
104 print "[download_finished]", string
105 Task.processFinished(self, 0)
107 class StickWizardJob(Job):
108 def __init__(self, path):
109 Job.__init__(self, _("USB stick wizard"))
112 while self.device[-1:] == "/" or self.device[-1:].isdigit():
113 self.device = self.device[:-1]
115 box = HardwareInfo().get_device_name()
116 url = "http://www.dreamboxupdate.com/download/opendreambox/dreambox-nfiflasher-%s.tar.bz2" % box
117 self.downloadfilename = "/tmp/dreambox-nfiflasher-%s.tar.bz2" % box
118 self.imagefilename = "/tmp/nfiflash_%s.img" % box
119 #UmountTask(self, device)
121 ImageDownloadTask(self, url, self.downloadfilename)
125 class PartitionTaskPostcondition(Condition):
126 def check(self, task):
127 return task.returncode == 0
129 def getErrorMessage(self, task):
131 task.ERROR_BLKRRPART: ("Device or resource busy"),
132 task.ERROR_UNKNOWN: (task.errormsg)
135 class PartitionTask(Task):
136 ERROR_UNKNOWN, ERROR_BLKRRPART = range(2)
137 def __init__(self, job):
138 Task.__init__(self, job, ("partitioning"))
139 self.postconditions.append(PartitionTaskPostcondition())
141 self.setTool("sfdisk")
142 self.args += [self.job.device]
144 self.initial_input = "0 - 0x6 *\n;\n;\n;\ny"
147 def run(self, callback):
148 Task.run(self, callback)
150 def processOutput(self, data):
151 print "[PartitionTask] output:", data
152 if data.startswith("BLKRRPART:"):
153 self.error = self.ERROR_BLKRRPART
155 self.error = self.ERROR_UNKNOWN
158 class UnpackTask(Task):
159 def __init__(self, job):
160 Task.__init__(self, job, ("Unpacking USB flasher image..."))
163 self.args += ["-xjvf", self.job.downloadfilename]
166 self.delayTimer = eTimer()
167 self.delayTimer.callback.append(self.progress_increment)
169 def run(self, callback):
170 Task.run(self, callback)
171 self.delayTimer.start(950, False)
173 def progress_increment(self):
176 def processOutput(self, data):
177 print "[UnpackTask] output: \'%s\'" % data
178 self.job.imagefilename = data
181 self.delayTimer.callback.remove(self.progress_increment)
183 class CopyTask(Task):
184 def __init__(self, job):
185 Task.__init__(self, job, ("Copying USB flasher boot image to stick..."))
188 self.args += ["if=%s" % self.job.imagefilename, "of=%s1" % self.job.device]
191 self.delayTimer = eTimer()
192 self.delayTimer.callback.append(self.progress_increment)
194 def run(self, callback):
195 Task.run(self, callback)
196 self.delayTimer.start(100, False)
198 def progress_increment(self):
201 def processOutput(self, data):
202 print "[CopyTask] output:", data
205 self.delayTimer.callback.remove(self.progress_increment)
207 class NFOViewer(Screen):
209 <screen name="NFOViewer" position="center,center" size="610,410" title="Changelog viewer" >
210 <widget name="changelog" position="10,10" size="590,380" font="Regular;16" />
213 def __init__(self, session, nfo):
214 Screen.__init__(self, session)
215 self["changelog"] = ScrollLabel(nfo)
217 self["ViewerActions"] = ActionMap(["SetupActions", "ColorActions", "DirectionActions"],
223 "down": self.pageDown,
227 self["changelog"].pageUp()
230 self["changelog"].pageDown()
235 class feedDownloader:
236 def __init__(self, feed_base, box, OE_vers):
237 print "[feedDownloader::init] feed_base=%s, box=%s" % (feed_base, box)
238 self.feed_base = feed_base
239 self.OE_vers = OE_vers
242 def getList(self, callback, errback):
243 self.urlbase = "%s/%s/%s/images/" % (self.feed_base, self.OE_vers, self.box)
244 print "[getList]", self.urlbase
245 self.callback = callback
246 self.errback = errback
247 client.getPage(self.urlbase).addCallback(self.feed_finished).addErrback(self.feed_failed)
249 def feed_failed(self, failure_instance):
250 print "[feed_failed]", str(failure_instance)
251 self.errback(failure_instance.getErrorMessage())
253 def feed_finished(self, feedhtml):
254 print "[feed_finished]"
255 fileresultmask = re.compile("<a class=[\'\"]nfi[\'\"] href=[\'\"](?P<url>.*?)[\'\"]>(?P<name>.*?.nfi)</a>", re.DOTALL)
256 searchresults = fileresultmask.finditer(feedhtml)
259 for x in searchresults:
261 if url[0:7] != "http://":
262 url = self.urlbase + x.group("url")
263 name = x.group("name")
265 fileresultlist.append(entry)
266 self.callback(fileresultlist, self.OE_vers)
268 class DeviceBrowser(Screen, HelpableScreen):
270 <screen name="DeviceBrowser" position="center,center" size="520,430" title="Please select target medium" >
271 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
272 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
273 <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" />
274 <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" />
275 <widget source="message" render="Label" position="5,50" size="510,150" font="Regular;16" />
276 <widget name="filelist" position="5,210" size="510,220" scrollbarMode="showOnDemand" />
279 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):
280 Screen.__init__(self, session)
282 HelpableScreen.__init__(self)
284 self["key_red"] = StaticText(_("Cancel"))
285 self["key_green"] = StaticText()
286 self["message"] = StaticText(message)
288 self.filelist = FileList(startdir, showDirectories = showDirectories, showFiles = showFiles, showMountpoints = showMountpoints, matchingPattern = matchingPattern, useServiceRef = useServiceRef, inhibitDirs = inhibitDirs, inhibitMounts = inhibitMounts, isTop = isTop, enableWrapAround = enableWrapAround, additionalExtensions = additionalExtensions)
289 self["filelist"] = self.filelist
291 self["FilelistActions"] = ActionMap(["SetupActions", "ColorActions"],
299 hotplugNotifier.append(self.hotplugCB)
300 self.onShown.append(self.updateButton)
301 self.onClose.append(self.removeHotplug)
303 def hotplugCB(self, dev, action):
304 print "[hotplugCB]", dev, action
307 def updateButton(self):
309 if self["filelist"].getFilename() or self["filelist"].getCurrentDirectory():
310 self["key_green"].text = _("Use")
312 self["key_green"].text = ""
314 def removeHotplug(self):
315 print "[removeHotplug]"
316 hotplugNotifier.remove(self.hotplugCB)
319 if self.filelist.canDescent():
320 if self["filelist"].showMountpoints == True and self["filelist"].showDirectories == False:
323 self.filelist.descent()
326 print "[use]", self["filelist"].getCurrentDirectory(), self["filelist"].getFilename()
327 if self["filelist"].getCurrentDirectory() is not None:
328 if self.filelist.canDescent() and self["filelist"].getFilename() and len(self["filelist"].getFilename()) > len(self["filelist"].getCurrentDirectory()):
329 self.filelist.descent()
330 self.close(self["filelist"].getCurrentDirectory())
331 elif self["filelist"].getFilename():
332 self.close(self["filelist"].getFilename())
337 (ALLIMAGES, RELEASE, EXPERIMENTAL, STICK_WIZARD, START) = range(5)
339 class NFIDownload(Screen):
341 <screen name="NFIDownload" position="center,center" size="610,410" title="NFIDownload" >
342 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
343 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
344 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
345 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
346 <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" />
347 <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" />
348 <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" />
349 <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" />
350 <ePixmap pixmap="skin_default/border_menu_350.png" position="5,50" zPosition="1" size="350,300" transparent="1" alphatest="on" />
351 <widget source="menu" render="Listbox" position="15,60" size="330,290" scrollbarMode="showOnDemand">
352 <convert type="TemplatedMultiContent">
355 MultiContentEntryText(pos = (2, 2), size = (330, 24), flags = RT_HALIGN_LEFT, text = 1), # index 0 is the MenuText,
356 ], True, "showOnDemand")
358 "fonts": [gFont("Regular", 22)],
363 <widget source="menu" render="Listbox" position="360,50" size="240,300" scrollbarMode="showNever" selectionDisabled="1">
364 <convert type="TemplatedMultiContent">
367 MultiContentEntryText(pos = (2, 2), size = (240, 300), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, text = 2), # index 2 is the Description,
368 ], False, "showNever")
370 "fonts": [gFont("Regular", 22)],
375 <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" />
378 def __init__(self, session, destdir=None):
379 Screen.__init__(self, session)
380 #self.skin_path = plugin_path
383 self.box = HardwareInfo().get_device_name()
384 self.feed_base = "http://www.dreamboxupdate.com/opendreambox" #/1.5/%s/images/" % self.box
385 self.usbmountpoint = "/mnt/usb/"
389 self["menu"] = List(self.menulist)
390 self["key_red"] = StaticText(_("Close"))
391 self["key_green"] = StaticText()
392 self["key_yellow"] = StaticText()
393 self["key_blue"] = StaticText()
395 self["status"] = StaticText(_("Please wait... Loading list..."))
397 self["shortcuts"] = ActionMap(["OkCancelActions", "ColorActions", "ShortcutActions", "DirectionActions"],
402 "blue": self.keyBlue,
404 "upRepeated": self.keyUp,
405 "downRepeated": self.keyDown,
406 "down": self.keyDown,
407 "cancel": self.close,
409 self.onShown.append(self.go)
410 self.feedlists = [[],[],[]]
412 self.container = eConsoleAppContainer()
413 self.container.dataAvail.append(self.tool_avail)
416 self.nfofilename = ""
418 self.target_dir = None
420 def tool_avail(self, string):
421 print "[tool_avail]" + string
422 self.taskstring += string
425 self.onShown.remove(self.go)
426 self["menu"].index = 0
427 url = "http://www.dreamboxupdate.com/download/opendreambox/dreambox-nfiflasher-%s-md5sums" % self.box
428 client.getPage(url).addCallback(self.md5sums_finished).addErrback(self.feed_failed)
430 def md5sums_finished(self, data):
431 print "[md5sums_finished]", data
432 self.stickimage_md5 = data
436 if self.branch == START:
440 self["menu"].setList(self.menulist)
441 #elif self.branch == ALLIMAGES or self.branch == STICK_WIZARD:
445 self.session.open(NFOViewer, self.nfo)
448 print "[keyOk]", self["menu"].getCurrent()
449 current = self["menu"].getCurrent()
451 if self.branch == START:
452 currentEntry = current[0]
453 if currentEntry == RELEASE:
455 self.branch = RELEASE
456 self.askDestination()
457 elif currentEntry == EXPERIMENTAL:
459 self.branch = EXPERIMENTAL
460 self.askDestination()
461 elif currentEntry == ALLIMAGES:
462 self.branch = ALLIMAGES
464 elif currentEntry == STICK_WIZARD:
465 self.askStartWizard()
466 elif self.branch == ALLIMAGES:
467 self.image_idx = self["menu"].getIndex()
468 self.askDestination()
472 self["menu"].selectPrevious()
476 self["menu"].selectNext()
479 def updateButtons(self):
480 current = self["menu"].getCurrent()
482 if self.branch == START:
483 self["key_red"].text = _("Close")
484 currentEntry = current[0]
485 if currentEntry in (RELEASE, EXPERIMENTAL):
486 self.nfo_download(currentEntry, 0)
487 self["key_green"].text = _("Download")
489 self.nfofilename = ""
491 self["key_blue"].text = ""
492 self["key_green"].text = _("continue")
494 elif self.branch == ALLIMAGES:
495 self["key_red"].text = _("Back")
496 self["key_green"].text = _("Download")
497 self.nfo_download(ALLIMAGES, self["menu"].getIndex())
499 def listImages(self):
502 mask = re.compile("%s/(?P<OE_vers>1\.\d)/%s/images/(?P<branch>.*?)-%s_(?P<version>.*?).nfi" % (self.feed_base, self.box, self.box), re.DOTALL)
503 for name, url in self.feedlists[ALLIMAGES]:
504 result = mask.match(url)
506 if result.group("version").startswith("20"):
507 version = ( result.group("version")[:4]+'-'+result.group("version")[4:6]+'-'+result.group("version")[6:8] )
509 version = result.group("version")
510 description = "\nOpendreambox %s\n%s image\n%s\n" % (result.group("OE_vers"), result.group("branch"), version)
511 imagelist.append((url, name, _("Download %s from Server" ) % description, None))
512 self["menu"].setList(imagelist)
514 def getUSBPartitions(self):
515 allpartitions = [ (r.description, r.mountpoint) for r in harddiskmanager.getMountedPartitions(onlyhotplug = True)]
516 print "[getUSBPartitions]", allpartitions
518 for x in allpartitions:
519 print x, x[1] == '/', x[0].find("USB"), access(x[1], R_OK)
520 if x[1] != '/' and x[0].find("USB") > -1: # and access(x[1], R_OK) is True:
521 usbpartition.append(x)
524 def askDestination(self):
525 usbpartition = self.getUSBPartitions()
526 if len(usbpartition) == 1:
527 self.target_dir = usbpartition[0][1]
528 self.ackDestinationDevice(device_description=usbpartition[0][0])
530 self.session.openWithCallback(self.DeviceBrowserClosed, DeviceBrowser, None, showDirectories=True, showMountpoints=True, inhibitMounts=["/autofs/sr0/"])
532 def DeviceBrowserClosed(self, path):
533 print "[DeviceBrowserClosed]", str(path)
534 self.target_dir = path
536 self.ackDestinationDevice()
540 def ackDestinationDevice(self, device_description=None):
541 if device_description == None:
542 dev = self.target_dir
544 dev = device_description
545 message = _("Do you want to download the image to %s ?") % (dev)
546 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.askDestination), (_("Cancel"),self.keyRed)]
547 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
549 def ackDestination_query(self, choice):
550 print "[ackDestination_query]", choice
551 if isinstance(choice, tuple):
556 def ackedDestination(self):
557 print "[ackedDestination]", self.branch, self.target_dir, self.target_dir[8:]
558 self.container.setCWD("/mnt")
559 if self.target_dir[:8] == "/autofs/":
560 self.target_dir = "/dev/" + self.target_dir[8:-1]
562 if self.branch == STICK_WIZARD:
563 job = StickWizardJob(self.target_dir)
564 job.afterEvent = "close"
565 job_manager.AddJob(job)
566 job_manager.failed_jobs = []
567 self.session.openWithCallback(self.StickWizardCB, JobView, job, afterEventChangeable = False)
569 elif self.branch != STICK_WIZARD:
570 url = self.feedlists[self.branch][self.image_idx][1]
571 filename = self.feedlists[self.branch][self.image_idx][0]
572 print "[getImage] start downloading %s to %s" % (url, filename)
573 job = ImageDownloadJob(url, filename, self.target_dir, self.usbmountpoint)
574 job.afterEvent = "close"
575 job_manager.AddJob(job)
576 job_manager.failed_jobs = []
577 self.session.openWithCallback(self.ImageDownloadCB, JobView, job, afterEventChangeable = False)
579 def StickWizardCB(self, ret=None):
580 print "[StickWizardCB]", ret
581 print job_manager.active_jobs, job_manager.failed_jobs, job_manager.job_classes, job_manager.in_background, job_manager.active_job
582 if len(job_manager.failed_jobs) == 0:
583 self.session.open(MessageBox, _("The USB stick was prepared to be bootable.\nNow you can download an NFI image file!"), type = MessageBox.TYPE_INFO)
584 if len(self.feedlists[ALLIMAGES]) == 0:
591 def ImageDownloadCB(self, ret):
592 print "[ImageDownloadCB]", ret
593 print job_manager.active_jobs, job_manager.failed_jobs, job_manager.job_classes, job_manager.in_background, job_manager.active_job
594 if len(job_manager.failed_jobs) == 0:
595 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)
600 self.feedDownloader15 = feedDownloader(self.feed_base, self.box, OE_vers="1.5")
601 self.feedDownloader16 = feedDownloader(self.feed_base, self.box, OE_vers="1.6")
602 self.feedlists = [[],[],[]]
603 self.feedDownloader15.getList(self.gotFeed, self.feed_failed)
604 self.feedDownloader16.getList(self.gotFeed, self.feed_failed)
606 def feed_failed(self, message=""):
607 self["status"].text = _("Could not connect to Dreambox .NFI Image Feed Server:") + "\n" + str(message) + "\n" + _("Please check your network settings!")
609 def gotFeed(self, feedlist, OE_vers):
610 print "[gotFeed]", OE_vers
612 experimentallist = []
614 for name, url in feedlist:
615 if name.find("release") > -1:
616 releaselist.append((name, url))
617 if name.find("experimental") > -1:
618 experimentallist.append((name, url))
619 self.feedlists[ALLIMAGES].append((name, url))
622 self.feedlists[RELEASE] = releaselist + self.feedlists[RELEASE]
623 self.feedlists[EXPERIMENTAL] = experimentallist + self.feedlists[RELEASE]
624 elif OE_vers == "1.5":
625 self.feedlists[RELEASE] = self.feedlists[RELEASE] + releaselist
626 self.feedlists[EXPERIMENTAL] = self.feedlists[EXPERIMENTAL] + experimentallist
630 def checkUSBStick(self):
631 self.target_dir = None
632 allpartitions = [ (r.description, r.mountpoint) for r in harddiskmanager.getMountedPartitions(onlyhotplug = True)]
633 print "[checkUSBStick] found partitions:", allpartitions
635 for x in allpartitions:
636 print x, x[1] == '/', x[0].find("USB"), access(x[1], R_OK)
637 if x[1] != '/' and x[0].find("USB") > -1: # and access(x[1], R_OK) is True:
638 usbpartition.append(x)
641 if len(usbpartition) == 1:
642 self.target_dir = usbpartition[0][1]
643 self.md5_passback = self.getFeed
644 self.md5_failback = self.askStartWizard
645 self.md5verify(self.stickimage_md5, self.target_dir)
646 elif usbpartition == []:
647 print "[NFIFlash] needs to create usb flasher stick first!"
648 self.askStartWizard()
650 self.askStartWizard()
652 def askStartWizard(self):
653 self.branch = STICK_WIZARD
654 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.
655 First, you need to prepare a USB stick so that it is bootable.
656 In the next step, an NFI image file can be downloaded from the update server and saved on the USB stick.
657 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!""")
658 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/"])
660 def wizardDeviceBrowserClosed(self, path):
661 print "[wizardDeviceBrowserClosed]", path
662 self.target_dir = path
664 self.md5_passback = self.getFeed
665 self.md5_failback = self.wizardQuery
666 self.md5verify(self.stickimage_md5, self.target_dir)
670 def wizardQuery(self):
671 print "[wizardQuery]"
672 description = self.target_dir
673 for name, dev in self.getUSBPartitions():
674 if dev == self.target_dir:
676 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"
677 message += _("The following device was found:\n\n%s\n\nDo you want to write the USB flasher to this stick?") % description
678 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.askStartWizard), (_("Cancel"),self.close)]
679 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
684 latest_release = "Release %s (Opendreambox 1.5)" % self.feedlists[RELEASE][0][0][-9:-4]
685 self.menulist.append((RELEASE, _("Get latest release image"), _("Download %s from Server" ) % latest_release, None))
690 dat = self.feedlists[EXPERIMENTAL][0][0][-12:-4]
691 latest_experimental = "Experimental %s-%s-%s (Opendreambox 1.6)" % (dat[:4], dat[4:6], dat[6:])
692 self.menulist.append((EXPERIMENTAL, _("Get latest experimental image"), _("Download %s from Server") % latest_experimental, None))
696 self.menulist.append((ALLIMAGES, _("Choose image to download"), _("Select desired image from feed list" ), None))
697 self.menulist.append((STICK_WIZARD, _("USB stick wizard"), _("Prepare another USB stick for image flashing" ), None))
698 self["menu"].setList(self.menulist)
699 self["status"].text = _("Currently installed image") + ": %s" % (about.getImageVersionString())
703 def nfo_download(self, branch, idx):
704 nfourl = (self.feedlists[branch][idx][1])[:-4]+".nfo"
705 self.nfofilename = (self.feedlists[branch][idx][0])[:-4]+".nfo"
706 print "[check_for_NFO]", nfourl
707 client.getPage(nfourl).addCallback(self.nfo_finished).addErrback(self.nfo_failed)
709 def nfo_failed(self, failure_instance):
710 print "[nfo_failed] " + str(failure_instance)
711 self["key_blue"].text = ""
712 self.nfofilename = ""
715 def nfo_finished(self,nfodata=""):
716 print "[nfo_finished] " + str(nfodata)
717 self["key_blue"].text = _("Changelog viewer")
720 def md5verify(self, md5, path):
722 print "[verify_md5]", md5, path, cmd
723 self.container.setCWD(path)
724 self.container.appClosed.append(self.md5finished)
725 self.container.execute(cmd)
726 self.container.write(md5)
727 self.container.dataSent.append(self.md5ready)
729 def md5ready(self, retval):
730 self.container.sendEOF()
732 def md5finished(self, retval):
733 print "[md5finished]", str(retval)
734 self.container.appClosed.remove(self.md5finished)
735 self.container.dataSent.remove(self.md5ready)
737 print "check passed! calling", repr(self.md5_passback)
740 print "check failed! calling", repr(self.md5_failback)
743 def main(session, **kwargs):
744 session.open(NFIDownload,"/home/root")
746 def filescan_open(list, session, **kwargs):
747 dev = "/dev/" + (list[0].path).rsplit('/',1)[0][7:]
748 print "mounting device " + dev + " to /mnt/usb..."
749 system("mount "+dev+" /mnt/usb/ -o rw,sync")
750 session.open(NFIDownload,"/mnt/usb/")
752 def filescan(**kwargs):
753 from Components.Scanner import Scanner, ScanPath
755 Scanner(mimetypes = ["application/x-dream-image"],
758 ScanPath(path = "", with_subdirs = False),
761 description = (_("Download .NFI-Files for USB-Flasher")+"..."),
762 openfnc = filescan_open, )