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, resolveFilename, SCOPE_HDD, SCOPE_MEDIA
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" >
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 = resolveFilename(SCOPE_MEDIA)+"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(resolveFilename(SCOPE_MEDIA)+"usb/")
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.openWithCallback(self.askBackupCB, MessageBox, _("The wizard can backup your current settings. Do you want to do a backup now?"), MessageBox.TYPE_YESNO)
616 self.umountCallback = self.keyRed
619 def askBackupCB(self, ret):
621 from Plugins.SystemPlugins.SoftwareManager.BackupRestore import BackupScreen
623 class USBBackupScreen(BackupScreen):
624 def __init__(self, session, usbmountpoint):
625 BackupScreen.__init__(self, session, runBackup = True)
626 self.backuppath = usbmountpoint
627 self.fullbackupfilename = self.backuppath + "/" + self.backupfile
629 self.session.openWithCallback(self.showHint, USBBackupScreen, self.usbmountpoint)
633 def showHint(self, ret=None):
634 self.session.open(MessageBox, _("To update your Dreambox firmware, please follow these steps:\n1) Turn off your box with the rear power switch and make sure the bootable USB stick is plugged in.\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)
635 self.umountCallback = self.keyRed
639 self.feedDownloader15 = feedDownloader(self.feed_base, self.box, OE_vers="1.5")
640 self.feedDownloader16 = feedDownloader(self.feed_base, self.box, OE_vers="1.6")
641 self.feedlists = [[],[],[]]
642 self.feedDownloader15.getList(self.gotFeed, self.feed_failed)
643 self.feedDownloader16.getList(self.gotFeed, self.feed_failed)
645 def feed_failed(self, message=""):
646 self["status"].text = _("Could not connect to Dreambox .NFI Image Feed Server:") + "\n" + str(message) + "\n" + _("Please check your network settings!")
648 def gotFeed(self, feedlist, OE_vers):
649 print "[gotFeed]", OE_vers
651 experimentallist = []
653 for name, url in feedlist:
654 if name.find("release") > -1:
655 releaselist.append((name, url))
656 if name.find("experimental") > -1:
657 experimentallist.append((name, url))
658 self.feedlists[ALLIMAGES].append((name, url))
661 self.feedlists[RELEASE] = releaselist + self.feedlists[RELEASE]
662 self.feedlists[EXPERIMENTAL] = experimentallist + self.feedlists[RELEASE]
663 elif OE_vers == "1.5":
664 self.feedlists[RELEASE] = self.feedlists[RELEASE] + releaselist
665 self.feedlists[EXPERIMENTAL] = self.feedlists[EXPERIMENTAL] + experimentallist
669 def checkUSBStick(self):
670 self.target_dir = None
671 allpartitions = [ (r.description, r.mountpoint) for r in harddiskmanager.getMountedPartitions(onlyhotplug = True)]
672 print "[checkUSBStick] found partitions:", allpartitions
674 for x in allpartitions:
675 print x, x[1] == '/', x[0].find("USB"), access(x[1], R_OK)
676 if x[1] != '/' and x[0].find("USB") > -1: # and access(x[1], R_OK) is True:
677 usbpartition.append(x)
680 if len(usbpartition) == 1:
681 self.target_dir = usbpartition[0][1]
682 self.md5_passback = self.getFeed
683 self.md5_failback = self.askStartWizard
684 self.md5verify(self.stickimage_md5, self.target_dir)
685 elif usbpartition == []:
686 print "[NFIFlash] needs to create usb flasher stick first!"
687 self.askStartWizard()
689 self.askStartWizard()
691 def askStartWizard(self):
692 self.branch = STICK_WIZARD
693 message = _("""This plugin creates a USB stick which can be used to update the firmware of your Dreambox without the need for a network or WLAN connection.
694 First, a USB stick needs to be prepared so that it becomes bootable.
695 In the next step, an NFI image file can be downloaded from the update server and saved on the USB stick.
696 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!""")
697 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/"])
699 def wizardDeviceBrowserClosed(self, path):
700 print "[wizardDeviceBrowserClosed]", path
701 self.target_dir = path
703 self.md5_passback = self.getFeed
704 self.md5_failback = self.wizardQuery
705 self.md5verify(self.stickimage_md5, self.target_dir)
709 def wizardQuery(self):
710 print "[wizardQuery]"
711 description = self.target_dir
712 for name, dev in self.getUSBPartitions():
713 if dev == self.target_dir:
715 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"
716 message += _("The following device was found:\n\n%s\n\nDo you want to write the USB flasher to this stick?") % description
717 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.askStartWizard), (_("Cancel"),self.close)]
718 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
723 latest_release = "Release %s (Opendreambox 1.5)" % self.feedlists[RELEASE][0][0][-9:-4]
724 self.menulist.append((RELEASE, _("Get latest release image"), _("Download %s from Server" ) % latest_release, None))
729 dat = self.feedlists[EXPERIMENTAL][0][0][-12:-4]
730 latest_experimental = "Experimental %s-%s-%s (Opendreambox 1.6)" % (dat[:4], dat[4:6], dat[6:])
731 self.menulist.append((EXPERIMENTAL, _("Get latest experimental image"), _("Download %s from Server") % latest_experimental, None))
735 self.menulist.append((ALLIMAGES, _("Choose image to download"), _("Select desired image from feed list" ), None))
736 self.menulist.append((STICK_WIZARD, _("USB stick wizard"), _("Prepare another USB stick for image flashing" ), None))
737 self["menu"].setList(self.menulist)
738 self["status"].text = _("Currently installed image") + ": %s" % (about.getImageVersionString())
742 def nfo_download(self, branch, idx):
743 nfourl = (self.feedlists[branch][idx][1])[:-4]+".nfo"
744 self.nfofilename = (self.feedlists[branch][idx][0])[:-4]+".nfo"
745 print "[check_for_NFO]", nfourl
746 client.getPage(nfourl).addCallback(self.nfo_finished).addErrback(self.nfo_failed)
748 def nfo_failed(self, failure_instance):
749 print "[nfo_failed] " + str(failure_instance)
750 self["key_blue"].text = ""
751 self.nfofilename = ""
754 def nfo_finished(self,nfodata=""):
755 print "[nfo_finished] " + str(nfodata)
756 self["key_blue"].text = _("Changelog")
759 def md5verify(self, md5, path):
761 print "[verify_md5]", md5, path, cmd
762 self.container.setCWD(path)
763 self.container.appClosed.append(self.md5finished)
764 self.container.execute(cmd)
765 self.container.write(md5)
766 self.container.dataSent.append(self.md5ready)
768 def md5ready(self, retval):
769 self.container.sendEOF()
771 def md5finished(self, retval):
772 print "[md5finished]", str(retval)
773 self.container.appClosed.remove(self.md5finished)
774 self.container.dataSent.remove(self.md5ready)
776 print "check passed! calling", repr(self.md5_passback)
779 print "check failed! calling", repr(self.md5_failback)
783 cmd = "umount " + self.usbmountpoint
784 print "[umount]", cmd
785 self.container.setCWD('/')
786 self.container.appClosed.append(self.umountFinished)
787 self.container.execute(cmd)
789 def umountFinished(self, retval):
790 print "[umountFinished]", str(retval)
791 self.container.appClosed.remove(self.umountFinished)
792 self.umountCallback()
794 def main(session, **kwargs):
795 session.open(NFIDownload,resolveFilename(SCOPE_HDD))
797 def filescan_open(list, session, **kwargs):
798 dev = "/dev/" + (list[0].path).rsplit('/',1)[0][7:]
799 print "mounting device " + dev + " to /media/usb..."
800 usbmountpoint = resolveFilename(SCOPE_MEDIA)+"usb/"
801 system("mount %s %s -o rw,sync" % (dev, usbmountpoint))
802 session.open(NFIDownload,usbmountpoint)
804 def filescan(**kwargs):
805 from Components.Scanner import Scanner, ScanPath
807 Scanner(mimetypes = ["application/x-dream-image"],
810 ScanPath(path = "", with_subdirs = False),
813 description = (_("Download .NFI-Files for USB-Flasher")+"..."),
814 openfnc = filescan_open, )