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
84 def run(self, callback):
85 self.callback = callback
86 self.download = downloadWithProgress(self.url,self.path)
87 self.download.addProgress(self.download_progress)
88 self.download.start().addCallback(self.download_finished).addErrback(self.download_failed)
89 print "[ImageDownloadTask] downloading", self.url, "to", self.path
92 print "[ImageDownloadTask] aborting", self.url
97 def download_progress(self, recvbytes, totalbytes):
98 #print "[update_progress] recvbytes=%d, totalbytes=%d" % (recvbytes, totalbytes)
99 if ( recvbytes - self.last_recvbytes ) > 10000: # anti-flicker
100 self.progress = int(100*(float(recvbytes)/float(totalbytes)))
101 self.name = _("Downloading") + ' ' + "%d of %d kBytes" % (recvbytes/1024, totalbytes/1024)
102 self.last_recvbytes = recvbytes
104 def download_failed(self, failure_instance=None, error_message=""):
105 self.error_message = error_message
106 if error_message == "" and failure_instance is not None:
107 self.error_message = failure_instance.getErrorMessage()
108 Task.processFinished(self, 1)
110 def download_finished(self, string=""):
112 self.finish(aborted = True)
114 Task.processFinished(self, 0)
116 class StickWizardJob(Job):
117 def __init__(self, path):
118 Job.__init__(self, _("USB stick wizard"))
121 while self.device[-1:] == "/" or self.device[-1:].isdigit():
122 self.device = self.device[:-1]
124 box = HardwareInfo().get_device_name()
125 url = "http://www.dreamboxupdate.com/download/opendreambox/dreambox-nfiflasher-%s.tar.bz2" % box
126 self.downloadfilename = "/tmp/dreambox-nfiflasher-%s.tar.bz2" % box
127 self.imagefilename = "/tmp/nfiflash_%s.img" % box
128 #UmountTask(self, device)
130 ImageDownloadTask(self, url, self.downloadfilename)
134 class PartitionTaskPostcondition(Condition):
135 def check(self, task):
136 return task.returncode == 0
138 def getErrorMessage(self, task):
140 task.ERROR_BLKRRPART: ("Device or resource busy"),
141 task.ERROR_UNKNOWN: (task.errormsg)
144 class PartitionTask(Task):
145 ERROR_UNKNOWN, ERROR_BLKRRPART = range(2)
146 def __init__(self, job):
147 Task.__init__(self, job, ("partitioning"))
148 self.postconditions.append(PartitionTaskPostcondition())
150 self.setTool("sfdisk")
151 self.args += [self.job.device]
153 self.initial_input = "0 - 0x6 *\n;\n;\n;\ny"
156 def run(self, callback):
157 Task.run(self, callback)
159 def processOutput(self, data):
160 print "[PartitionTask] output:", data
161 if data.startswith("BLKRRPART:"):
162 self.error = self.ERROR_BLKRRPART
164 self.error = self.ERROR_UNKNOWN
167 class UnpackTask(Task):
168 def __init__(self, job):
169 Task.__init__(self, job, ("Unpacking USB flasher image..."))
172 self.args += ["-xjvf", self.job.downloadfilename]
175 self.delayTimer = eTimer()
176 self.delayTimer.callback.append(self.progress_increment)
178 def run(self, callback):
179 Task.run(self, callback)
180 self.delayTimer.start(950, False)
182 def progress_increment(self):
185 def processOutput(self, data):
186 print "[UnpackTask] output: \'%s\'" % data
187 self.job.imagefilename = data
190 self.delayTimer.callback.remove(self.progress_increment)
192 class CopyTask(Task):
193 def __init__(self, job):
194 Task.__init__(self, job, ("Copying USB flasher boot image to stick..."))
197 self.args += ["if=%s" % self.job.imagefilename, "of=%s1" % self.job.device]
200 self.delayTimer = eTimer()
201 self.delayTimer.callback.append(self.progress_increment)
203 def run(self, callback):
204 Task.run(self, callback)
205 self.delayTimer.start(100, False)
207 def progress_increment(self):
210 def processOutput(self, data):
211 print "[CopyTask] output:", data
214 self.delayTimer.callback.remove(self.progress_increment)
216 class NFOViewer(Screen):
218 <screen name="NFOViewer" position="center,center" size="610,410" title="Changelog viewer" >
219 <widget name="changelog" position="10,10" size="590,380" font="Regular;16" />
222 def __init__(self, session, nfo):
223 Screen.__init__(self, session)
224 self["changelog"] = ScrollLabel(nfo)
226 self["ViewerActions"] = ActionMap(["SetupActions", "ColorActions", "DirectionActions"],
232 "down": self.pageDown,
236 self["changelog"].pageUp()
239 self["changelog"].pageDown()
244 class feedDownloader:
245 def __init__(self, feed_base, box, OE_vers):
246 print "[feedDownloader::init] feed_base=%s, box=%s" % (feed_base, box)
247 self.feed_base = feed_base
248 self.OE_vers = OE_vers
251 def getList(self, callback, errback):
252 self.urlbase = "%s/%s/%s/images/" % (self.feed_base, self.OE_vers, self.box)
253 print "[getList]", self.urlbase
254 self.callback = callback
255 self.errback = errback
256 client.getPage(self.urlbase).addCallback(self.feed_finished).addErrback(self.feed_failed)
258 def feed_failed(self, failure_instance):
259 print "[feed_failed]", str(failure_instance)
260 self.errback(failure_instance.getErrorMessage())
262 def feed_finished(self, feedhtml):
263 print "[feed_finished]"
264 fileresultmask = re.compile("<a class=[\'\"]nfi[\'\"] href=[\'\"](?P<url>.*?)[\'\"]>(?P<name>.*?.nfi)</a>", re.DOTALL)
265 searchresults = fileresultmask.finditer(feedhtml)
268 for x in searchresults:
270 if url[0:7] != "http://":
271 url = self.urlbase + x.group("url")
272 name = x.group("name")
274 fileresultlist.append(entry)
275 self.callback(fileresultlist, self.OE_vers)
277 class DeviceBrowser(Screen, HelpableScreen):
279 <screen name="DeviceBrowser" position="center,center" size="520,430" title="Please select target medium" >
280 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
281 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
282 <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" />
283 <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" />
284 <widget source="message" render="Label" position="5,50" size="510,150" font="Regular;16" />
285 <widget name="filelist" position="5,210" size="510,220" scrollbarMode="showOnDemand" />
288 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):
289 Screen.__init__(self, session)
291 HelpableScreen.__init__(self)
293 self["key_red"] = StaticText(_("Cancel"))
294 self["key_green"] = StaticText()
295 self["message"] = StaticText(message)
297 self.filelist = FileList(startdir, showDirectories = showDirectories, showFiles = showFiles, showMountpoints = showMountpoints, matchingPattern = matchingPattern, useServiceRef = useServiceRef, inhibitDirs = inhibitDirs, inhibitMounts = inhibitMounts, isTop = isTop, enableWrapAround = enableWrapAround, additionalExtensions = additionalExtensions)
298 self["filelist"] = self.filelist
300 self["FilelistActions"] = ActionMap(["SetupActions", "ColorActions"],
308 hotplugNotifier.append(self.hotplugCB)
309 self.onShown.append(self.updateButton)
310 self.onClose.append(self.removeHotplug)
312 def hotplugCB(self, dev, action):
313 print "[hotplugCB]", dev, action
316 def updateButton(self):
318 if self["filelist"].getFilename() or self["filelist"].getCurrentDirectory():
319 self["key_green"].text = _("Use")
321 self["key_green"].text = ""
323 def removeHotplug(self):
324 print "[removeHotplug]"
325 hotplugNotifier.remove(self.hotplugCB)
328 if self.filelist.canDescent():
329 if self["filelist"].showMountpoints == True and self["filelist"].showDirectories == False:
332 self.filelist.descent()
335 print "[use]", self["filelist"].getCurrentDirectory(), self["filelist"].getFilename()
336 if self["filelist"].getCurrentDirectory() is not None:
337 if self.filelist.canDescent() and self["filelist"].getFilename() and len(self["filelist"].getFilename()) > len(self["filelist"].getCurrentDirectory()):
338 self.filelist.descent()
339 self.close(self["filelist"].getCurrentDirectory())
340 elif self["filelist"].getFilename():
341 self.close(self["filelist"].getFilename())
346 (ALLIMAGES, RELEASE, EXPERIMENTAL, STICK_WIZARD, START) = range(5)
348 class NFIDownload(Screen):
350 <screen name="NFIDownload" position="center,center" size="610,410" title="NFIDownload" >
351 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
352 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
353 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
354 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
355 <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" />
356 <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" />
357 <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" />
358 <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" />
359 <ePixmap pixmap="skin_default/border_menu_350.png" position="5,50" zPosition="1" size="350,300" transparent="1" alphatest="on" />
360 <widget source="menu" render="Listbox" position="15,60" size="330,290" scrollbarMode="showOnDemand">
361 <convert type="TemplatedMultiContent">
364 MultiContentEntryText(pos = (2, 2), size = (330, 24), flags = RT_HALIGN_LEFT, text = 1), # index 0 is the MenuText,
365 ], True, "showOnDemand")
367 "fonts": [gFont("Regular", 22)],
372 <widget source="menu" render="Listbox" position="360,50" size="240,300" scrollbarMode="showNever" selectionDisabled="1">
373 <convert type="TemplatedMultiContent">
376 MultiContentEntryText(pos = (2, 2), size = (240, 300), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, text = 2), # index 2 is the Description,
377 ], False, "showNever")
379 "fonts": [gFont("Regular", 22)],
384 <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" />
387 def __init__(self, session, destdir=None):
388 Screen.__init__(self, session)
389 #self.skin_path = plugin_path
392 self.box = HardwareInfo().get_device_name()
393 self.feed_base = "http://www.dreamboxupdate.com/opendreambox" #/1.5/%s/images/" % self.box
394 self.usbmountpoint = "/mnt/usb/"
398 self["menu"] = List(self.menulist)
399 self["key_red"] = StaticText(_("Close"))
400 self["key_green"] = StaticText()
401 self["key_yellow"] = StaticText()
402 self["key_blue"] = StaticText()
404 self["status"] = StaticText(_("Please wait... Loading list..."))
406 self["shortcuts"] = ActionMap(["OkCancelActions", "ColorActions", "ShortcutActions", "DirectionActions"],
411 "blue": self.keyBlue,
413 "upRepeated": self.keyUp,
414 "downRepeated": self.keyDown,
415 "down": self.keyDown,
416 "cancel": self.close,
418 self.onShown.append(self.go)
419 self.feedlists = [[],[],[]]
421 self.container = eConsoleAppContainer()
422 self.container.dataAvail.append(self.tool_avail)
425 self.nfofilename = ""
427 self.target_dir = None
429 def tool_avail(self, string):
430 print "[tool_avail]" + string
431 self.taskstring += string
434 self.onShown.remove(self.go)
435 self.umountCallback = self.getMD5
439 url = "http://www.dreamboxupdate.com/download/opendreambox/dreambox-nfiflasher-%s-md5sums" % self.box
440 client.getPage(url).addCallback(self.md5sums_finished).addErrback(self.feed_failed)
442 def md5sums_finished(self, data):
443 print "[md5sums_finished]", data
444 self.stickimage_md5 = data
448 if self.branch == START:
452 self["menu"].setList(self.menulist)
453 #elif self.branch == ALLIMAGES or self.branch == STICK_WIZARD:
457 self.session.open(NFOViewer, self.nfo)
460 print "[keyOk]", self["menu"].getCurrent()
461 current = self["menu"].getCurrent()
463 if self.branch == START:
464 currentEntry = current[0]
465 if currentEntry == RELEASE:
467 self.branch = RELEASE
468 self.askDestination()
469 elif currentEntry == EXPERIMENTAL:
471 self.branch = EXPERIMENTAL
472 self.askDestination()
473 elif currentEntry == ALLIMAGES:
474 self.branch = ALLIMAGES
476 elif currentEntry == STICK_WIZARD:
477 self.askStartWizard()
478 elif self.branch == ALLIMAGES:
479 self.image_idx = self["menu"].getIndex()
480 self.askDestination()
484 self["menu"].selectPrevious()
488 self["menu"].selectNext()
491 def updateButtons(self):
492 current = self["menu"].getCurrent()
494 if self.branch == START:
495 self["key_red"].text = _("Close")
496 currentEntry = current[0]
497 if currentEntry in (RELEASE, EXPERIMENTAL):
498 self.nfo_download(currentEntry, 0)
499 self["key_green"].text = _("Download")
501 self.nfofilename = ""
503 self["key_blue"].text = ""
504 self["key_green"].text = _("continue")
506 elif self.branch == ALLIMAGES:
507 self["key_red"].text = _("Back")
508 self["key_green"].text = _("Download")
509 self.nfo_download(ALLIMAGES, self["menu"].getIndex())
511 def listImages(self):
514 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)
515 for name, url in self.feedlists[ALLIMAGES]:
516 result = mask.match(url)
518 if result.group("version").startswith("20"):
519 version = ( result.group("version")[:4]+'-'+result.group("version")[4:6]+'-'+result.group("version")[6:8] )
521 version = result.group("version")
522 description = "\nOpendreambox %s\n%s image\n%s\n" % (result.group("OE_vers"), result.group("branch"), version)
523 imagelist.append((url, name, _("Download %s from Server" ) % description, None))
524 self["menu"].setList(imagelist)
526 def getUSBPartitions(self):
527 allpartitions = [ (r.description, r.mountpoint) for r in harddiskmanager.getMountedPartitions(onlyhotplug = True)]
528 print "[getUSBPartitions]", allpartitions
530 for x in allpartitions:
531 print x, x[1] == '/', x[0].find("USB"), access(x[1], R_OK)
532 if x[1] != '/' and x[0].find("USB") > -1: # and access(x[1], R_OK) is True:
533 usbpartition.append(x)
536 def askDestination(self):
537 usbpartition = self.getUSBPartitions()
538 if len(usbpartition) == 1:
539 self.target_dir = usbpartition[0][1]
540 self.ackDestinationDevice(device_description=usbpartition[0][0])
542 self.openDeviceBrowser()
544 def openDeviceBrowser(self):
545 self.session.openWithCallback(self.DeviceBrowserClosed, DeviceBrowser, None, showDirectories=True, showMountpoints=True, inhibitMounts=["/autofs/sr0/"])
547 def DeviceBrowserClosed(self, path):
548 print "[DeviceBrowserClosed]", str(path)
549 self.target_dir = path
551 self.ackDestinationDevice()
555 def ackDestinationDevice(self, device_description=None):
556 if device_description == None:
557 dev = self.target_dir
559 dev = device_description
560 message = _("Do you want to download the image to %s ?") % (dev)
561 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.openDeviceBrowser), (_("Cancel"),self.keyRed)]
562 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
564 def ackDestination_query(self, choice):
565 print "[ackDestination_query]", choice
566 if isinstance(choice, tuple):
571 def ackedDestination(self):
572 print "[ackedDestination]", self.branch, self.target_dir
573 self.container.setCWD("/mnt")
574 if self.target_dir[:8] == "/autofs/":
575 self.target_dir = "/dev/" + self.target_dir[8:-1]
577 if self.branch == STICK_WIZARD:
578 job = StickWizardJob(self.target_dir)
579 job.afterEvent = "close"
580 job_manager.AddJob(job)
581 job_manager.failed_jobs = []
582 self.session.openWithCallback(self.StickWizardCB, JobView, job, afterEventChangeable = False)
584 elif self.branch != STICK_WIZARD:
585 url = self.feedlists[self.branch][self.image_idx][1]
586 filename = self.feedlists[self.branch][self.image_idx][0]
587 print "[getImage] start downloading %s to %s" % (url, filename)
588 if self.target_dir.startswith("/dev/"):
589 job = ImageDownloadJob(url, filename, self.target_dir, self.usbmountpoint)
591 job = ImageDownloadJob(url, filename, None, self.target_dir)
592 job.afterEvent = "close"
593 job_manager.AddJob(job)
594 job_manager.failed_jobs = []
595 self.session.openWithCallback(self.ImageDownloadCB, JobView, job, afterEventChangeable = False)
597 def StickWizardCB(self, ret=None):
598 print "[StickWizardCB]", ret
599 # print job_manager.active_jobs, job_manager.failed_jobs, job_manager.job_classes, job_manager.in_background, job_manager.active_job
600 if len(job_manager.failed_jobs) == 0:
601 self.session.open(MessageBox, _("The USB stick was prepared to be bootable.\nNow you can download an NFI image file!"), type = MessageBox.TYPE_INFO)
602 if len(self.feedlists[ALLIMAGES]) == 0:
607 self.umountCallback = self.checkUSBStick
610 def ImageDownloadCB(self, ret):
611 print "[ImageDownloadCB]", ret
612 # print job_manager.active_jobs, job_manager.failed_jobs, job_manager.job_classes, job_manager.in_background, job_manager.active_job
613 if len(job_manager.failed_jobs) == 0:
614 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)
616 self.umountCallback = self.keyRed
620 self.feedDownloader15 = feedDownloader(self.feed_base, self.box, OE_vers="1.5")
621 self.feedDownloader16 = feedDownloader(self.feed_base, self.box, OE_vers="1.6")
622 self.feedlists = [[],[],[]]
623 self.feedDownloader15.getList(self.gotFeed, self.feed_failed)
624 self.feedDownloader16.getList(self.gotFeed, self.feed_failed)
626 def feed_failed(self, message=""):
627 self["status"].text = _("Could not connect to Dreambox .NFI Image Feed Server:") + "\n" + str(message) + "\n" + _("Please check your network settings!")
629 def gotFeed(self, feedlist, OE_vers):
630 print "[gotFeed]", OE_vers
632 experimentallist = []
634 for name, url in feedlist:
635 if name.find("release") > -1:
636 releaselist.append((name, url))
637 if name.find("experimental") > -1:
638 experimentallist.append((name, url))
639 self.feedlists[ALLIMAGES].append((name, url))
642 self.feedlists[RELEASE] = releaselist + self.feedlists[RELEASE]
643 self.feedlists[EXPERIMENTAL] = experimentallist + self.feedlists[RELEASE]
644 elif OE_vers == "1.5":
645 self.feedlists[RELEASE] = self.feedlists[RELEASE] + releaselist
646 self.feedlists[EXPERIMENTAL] = self.feedlists[EXPERIMENTAL] + experimentallist
650 def checkUSBStick(self):
651 self.target_dir = None
652 allpartitions = [ (r.description, r.mountpoint) for r in harddiskmanager.getMountedPartitions(onlyhotplug = True)]
653 print "[checkUSBStick] found partitions:", allpartitions
655 for x in allpartitions:
656 print x, x[1] == '/', x[0].find("USB"), access(x[1], R_OK)
657 if x[1] != '/' and x[0].find("USB") > -1: # and access(x[1], R_OK) is True:
658 usbpartition.append(x)
661 if len(usbpartition) == 1:
662 self.target_dir = usbpartition[0][1]
663 self.md5_passback = self.getFeed
664 self.md5_failback = self.askStartWizard
665 self.md5verify(self.stickimage_md5, self.target_dir)
666 elif usbpartition == []:
667 print "[NFIFlash] needs to create usb flasher stick first!"
668 self.askStartWizard()
670 self.askStartWizard()
672 def askStartWizard(self):
673 self.branch = STICK_WIZARD
674 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.
675 First, you need to prepare a USB stick so that it is bootable.
676 In the next step, an NFI image file can be downloaded from the update server and saved on the USB stick.
677 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!""")
678 self.session.openWithCallback(self.wizardDeviceBrowserClosed, DeviceBrowser, None, message, showDirectories=True, showMountpoints=True, inhibitMounts=["/","/autofs/sr0/","/autofs/sda1/","/media/hdd/","/media/net/",self.usbmountpoint,"/media/dvd/"])
680 def wizardDeviceBrowserClosed(self, path):
681 print "[wizardDeviceBrowserClosed]", path
682 self.target_dir = path
684 self.md5_passback = self.getFeed
685 self.md5_failback = self.wizardQuery
686 self.md5verify(self.stickimage_md5, self.target_dir)
690 def wizardQuery(self):
691 print "[wizardQuery]"
692 description = self.target_dir
693 for name, dev in self.getUSBPartitions():
694 if dev == self.target_dir:
696 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"
697 message += _("The following device was found:\n\n%s\n\nDo you want to write the USB flasher to this stick?") % description
698 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.askStartWizard), (_("Cancel"),self.close)]
699 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
704 latest_release = "Release %s (Opendreambox 1.5)" % self.feedlists[RELEASE][0][0][-9:-4]
705 self.menulist.append((RELEASE, _("Get latest release image"), _("Download %s from Server" ) % latest_release, None))
710 dat = self.feedlists[EXPERIMENTAL][0][0][-12:-4]
711 latest_experimental = "Experimental %s-%s-%s (Opendreambox 1.6)" % (dat[:4], dat[4:6], dat[6:])
712 self.menulist.append((EXPERIMENTAL, _("Get latest experimental image"), _("Download %s from Server") % latest_experimental, None))
716 self.menulist.append((ALLIMAGES, _("Choose image to download"), _("Select desired image from feed list" ), None))
717 self.menulist.append((STICK_WIZARD, _("USB stick wizard"), _("Prepare another USB stick for image flashing" ), None))
718 self["menu"].setList(self.menulist)
719 self["status"].text = _("Currently installed image") + ": %s" % (about.getImageVersionString())
723 def nfo_download(self, branch, idx):
724 nfourl = (self.feedlists[branch][idx][1])[:-4]+".nfo"
725 self.nfofilename = (self.feedlists[branch][idx][0])[:-4]+".nfo"
726 print "[check_for_NFO]", nfourl
727 client.getPage(nfourl).addCallback(self.nfo_finished).addErrback(self.nfo_failed)
729 def nfo_failed(self, failure_instance):
730 print "[nfo_failed] " + str(failure_instance)
731 self["key_blue"].text = ""
732 self.nfofilename = ""
735 def nfo_finished(self,nfodata=""):
736 print "[nfo_finished] " + str(nfodata)
737 self["key_blue"].text = _("Changelog viewer")
740 def md5verify(self, md5, path):
742 print "[verify_md5]", md5, path, cmd
743 self.container.setCWD(path)
744 self.container.appClosed.append(self.md5finished)
745 self.container.execute(cmd)
746 self.container.write(md5)
747 self.container.dataSent.append(self.md5ready)
749 def md5ready(self, retval):
750 self.container.sendEOF()
752 def md5finished(self, retval):
753 print "[md5finished]", str(retval)
754 self.container.appClosed.remove(self.md5finished)
755 self.container.dataSent.remove(self.md5ready)
757 print "check passed! calling", repr(self.md5_passback)
760 print "check failed! calling", repr(self.md5_failback)
764 cmd = "umount " + self.usbmountpoint
765 print "[umount]", cmd
766 self.container.setCWD('/')
767 self.container.appClosed.append(self.umountFinished)
768 self.container.execute(cmd)
770 def umountFinished(self, retval):
771 print "[umountFinished]", str(retval)
772 self.container.appClosed.remove(self.umountFinished)
773 self.umountCallback()
775 def main(session, **kwargs):
776 session.open(NFIDownload,"/home/root")
778 def filescan_open(list, session, **kwargs):
779 dev = "/dev/" + (list[0].path).rsplit('/',1)[0][7:]
780 print "mounting device " + dev + " to /mnt/usb..."
781 system("mount "+dev+" /mnt/usb/ -o rw,sync")
782 session.open(NFIDownload,"/mnt/usb/")
784 def filescan(**kwargs):
785 from Components.Scanner import Scanner, ScanPath
787 Scanner(mimetypes = ["application/x-dream-image"],
790 ScanPath(path = "", with_subdirs = False),
793 description = (_("Download .NFI-Files for USB-Flasher")+"..."),
794 openfnc = filescan_open, )