Merge branch 'master' of fraxinas@git.opendreambox.org:/git/enigma2
[enigma2.git] / lib / python / Plugins / SystemPlugins / NFIFlash / downloader.py
index 579e4cebe85083414e8b293b02637c37c5db61f3..c91c85888b91a73a31b97e66b9f26b360c74bae0 100644 (file)
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 from Components.MenuList import MenuList
 from Screens.Screen import Screen
 from Screens.MessageBox import MessageBox
 from Components.MenuList import MenuList
 from Screens.Screen import Screen
 from Screens.MessageBox import MessageBox
@@ -18,6 +19,7 @@ import urllib
 from twisted.web import client
 from twisted.internet import reactor, defer
 from twisted.python import failure
 from twisted.web import client
 from twisted.internet import reactor, defer
 from twisted.python import failure
+from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
 
 class UserRequestedCancel(Exception):
        pass
 
 class UserRequestedCancel(Exception):
        pass
@@ -35,7 +37,7 @@ class HTTPProgressDownloader(client.HTTPDownloader):
                        client.HTTPDownloader.page(self, "")
                else:
                        client.HTTPDownloader.noPage(self, reason)
                        client.HTTPDownloader.page(self, "")
                else:
                        client.HTTPDownloader.noPage(self, reason)
-       
+
        def gotHeaders(self, headers):
                if self.status == "200":
                        if headers.has_key("content-length"):
        def gotHeaders(self, headers):
                if self.status == "200":
                        if headers.has_key("content-length"):
@@ -44,14 +46,14 @@ class HTTPProgressDownloader(client.HTTPDownloader):
                                self.totalbytes = 0
                        self.currentbytes = 0.0
                return client.HTTPDownloader.gotHeaders(self, headers)
                                self.totalbytes = 0
                        self.currentbytes = 0.0
                return client.HTTPDownloader.gotHeaders(self, headers)
-       
+
        def pagePart(self, packet):
                if self.status == "200":
                        self.currentbytes += len(packet)
                if self.totalbytes and self.progress_callback:
                        self.progress_callback(self.currentbytes, self.totalbytes)
                return client.HTTPDownloader.pagePart(self, packet)
        def pagePart(self, packet):
                if self.status == "200":
                        self.currentbytes += len(packet)
                if self.totalbytes and self.progress_callback:
                        self.progress_callback(self.currentbytes, self.totalbytes)
                return client.HTTPDownloader.pagePart(self, packet)
-       
+
        def pageEnd(self):
                return client.HTTPDownloader.pageEnd(self)
 
        def pageEnd(self):
                return client.HTTPDownloader.pageEnd(self)
 
@@ -60,10 +62,10 @@ class downloadWithProgress:
                scheme, host, port, path = client._parse(url)
                self.factory = HTTPProgressDownloader(url, outputfile, *args, **kwargs)
                self.connection = reactor.connectTCP(host, port, self.factory)
                scheme, host, port, path = client._parse(url)
                self.factory = HTTPProgressDownloader(url, outputfile, *args, **kwargs)
                self.connection = reactor.connectTCP(host, port, self.factory)
-       
+
        def start(self):
                return self.factory.deferred
        def start(self):
                return self.factory.deferred
-       
+
        def stop(self):
                print "[stop]"
                self.connection.disconnect()
        def stop(self):
                print "[stop]"
                self.connection.disconnect()
@@ -86,11 +88,11 @@ class Feedlist(MenuList):
        def getNFIname(self):
                l = self.l.getCurrentSelection()
                return l and l[0][0]
        def getNFIname(self):
                l = self.l.getCurrentSelection()
                return l and l[0][0]
-       
+
        def getNFIurl(self):
                l = self.l.getCurrentSelection()
                return l and l[0][1]
        def getNFIurl(self):
                l = self.l.getCurrentSelection()
                return l and l[0][1]
-       
+
        def getNFOname(self):
                l = self.l.getCurrentSelection()
                return l and l[0][0][:-3]+"nfo"
        def getNFOname(self):
                l = self.l.getCurrentSelection()
                return l and l[0][0][:-3]+"nfo"
@@ -105,7 +107,7 @@ class Feedlist(MenuList):
                        return False
                else:
                        return True
                        return False
                else:
                        return True
-       
+
        def moveSelection(self,idx=0):
                if self.instance is not None:
                        self.instance.moveSelectionTo(idx)
        def moveSelection(self,idx=0):
                if self.instance is not None:
                        self.instance.moveSelectionTo(idx)
@@ -119,10 +121,10 @@ class NFIDownload(Screen):
                        <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
                        <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
                        <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
                        <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
                        <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
                        <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
-                       <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" />
-                       <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" />
-                       <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" />
-                       <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" />
+                       <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;19" valign="center" halign="center" backgroundColor="#9f1313" transparent="1" />
+                       <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;19" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
+                       <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;19" valign="center" halign="center" backgroundColor="#a08500" transparent="1" />
+                       <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;19" valign="center" halign="center" backgroundColor="#18188b" transparent="1" />
                        
                        <widget source="label_top" render="Label" position="10,44" size="240,20" font="Regular;16" />
                        <widget name="feedlist" position="10,66" size="250,222" scrollbarMode="showOnDemand" />
                        
                        <widget source="label_top" render="Label" position="10,44" size="240,20" font="Regular;16" />
                        <widget name="feedlist" position="10,66" size="250,222" scrollbarMode="showOnDemand" />
@@ -169,7 +171,8 @@ class NFIDownload(Screen):
                self.box = HardwareInfo().get_device_name()
                self.feed_base = "http://www.dreamboxupdate.com/opendreambox/1.5/%s/images/" % self.box
                self.nfi_filter = "" # "release" # only show NFIs containing this string, or all if ""
                self.box = HardwareInfo().get_device_name()
                self.feed_base = "http://www.dreamboxupdate.com/opendreambox/1.5/%s/images/" % self.box
                self.nfi_filter = "" # "release" # only show NFIs containing this string, or all if ""
-               
+               self.wizard_mode = False
+
                self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "DirectionActions", "EPGSelectActions"],
                {
                        "cancel": self.closeCB,
                self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "DirectionActions", "EPGSelectActions"],
                {
                        "cancel": self.closeCB,
@@ -187,16 +190,15 @@ class NFIDownload(Screen):
                        "downRepeated": self.down,
                        "down": self.down
                }, -1)
                        "downRepeated": self.down,
                        "down": self.down
                }, -1)
-               
+
                self.feed_download()
                self.feed_download()
-       
+
        def downloading(self, state=True):
                if state is True:       
                        self["key_red"].text = _("Cancel")
                        self["key_green"].text = ""
                        self["key_yellow"].text = ""
                        self["key_blue"].text = ""
        def downloading(self, state=True):
                if state is True:       
                        self["key_red"].text = _("Cancel")
                        self["key_green"].text = ""
                        self["key_yellow"].text = ""
                        self["key_blue"].text = ""
-                       
                else:
                        self.download = None
                        self["key_red"].text = _("Exit")
                else:
                        self.download = None
                        self["key_red"].text = _("Exit")
@@ -206,21 +208,21 @@ class NFIDownload(Screen):
                                        self["key_yellow"].text = (_("Change dir."))
                                else:
                                        self["key_yellow"].text = (_("Select image"))
                                        self["key_yellow"].text = (_("Change dir."))
                                else:
                                        self["key_yellow"].text = (_("Select image"))
-                       self["key_blue"].text = (_("Fix USB stick"))
-               
+                       self["key_blue"].text = (_("USB stick wizard"))
+
        def switchList(self,to_where=None):
                if self.download or not self["feedlist"].isValid():
                        return
        def switchList(self,to_where=None):
                if self.download or not self["feedlist"].isValid():
                        return
-               
+
                self["job_progressbar"].value = 0
                self["job_progresslabel"].text = ""
                self["job_progressbar"].value = 0
                self["job_progresslabel"].text = ""
-               
+
                if to_where is None:
                        if self.focus is self.LIST_SOURCE:
                                to_where = self.LIST_DEST
                        if self.focus is self.LIST_DEST:
                                to_where = self.LIST_SOURCE
                if to_where is None:
                        if self.focus is self.LIST_SOURCE:
                                to_where = self.LIST_DEST
                        if self.focus is self.LIST_DEST:
                                to_where = self.LIST_SOURCE
-                               
+
                if to_where is self.LIST_DEST:
                        self.focus = self.LIST_DEST
                        self["statusbar"].text = _("Please select target directory or medium")
                if to_where is self.LIST_DEST:
                        self.focus = self.LIST_DEST
                        self["statusbar"].text = _("Please select target directory or medium")
@@ -230,7 +232,7 @@ class NFIDownload(Screen):
                        self["label_bottom"].text = _("Selected source image")+":"
                        self["path_bottom"].text = str(self["feedlist"].getNFIname())
                        self["key_yellow"].text = (_("Select image"))
                        self["label_bottom"].text = _("Selected source image")+":"
                        self["path_bottom"].text = str(self["feedlist"].getNFIname())
                        self["key_yellow"].text = (_("Select image"))
-               
+
                elif to_where is self.LIST_SOURCE:
                        self.focus = self.LIST_SOURCE
                        self["statusbar"].text = _("Please choose .NFI image file from feed server to download")
                elif to_where is self.LIST_SOURCE:
                        self.focus = self.LIST_SOURCE
                        self["statusbar"].text = _("Please choose .NFI image file from feed server to download")
@@ -240,7 +242,7 @@ class NFIDownload(Screen):
                        self["label_bottom"].text = _("Destination directory")+":"
                        self["path_bottom"].text = str(self["destlist"].getCurrentDirectory())
                        self["key_yellow"].text = (_("Change dir."))
                        self["label_bottom"].text = _("Destination directory")+":"
                        self["path_bottom"].text = str(self["destlist"].getCurrentDirectory())
                        self["key_yellow"].text = (_("Change dir."))
-                       
+
        def up(self):
                if self.download:
                        return
        def up(self):
                if self.download:
                        return
@@ -249,7 +251,7 @@ class NFIDownload(Screen):
                        self.nfo_download()
                if self.focus is self.LIST_DEST:
                        self["destlist"].up()
                        self.nfo_download()
                if self.focus is self.LIST_DEST:
                        self["destlist"].up()
-       
+
        def down(self):
                if self.download:
                        return
        def down(self):
                if self.download:
                        return
@@ -258,7 +260,7 @@ class NFIDownload(Screen):
                        self.nfo_download()
                if self.focus is self.LIST_DEST:
                        self["destlist"].down()
                        self.nfo_download()
                if self.focus is self.LIST_DEST:
                        self["destlist"].down()
-                       
+
        def left(self):
                if self.download:
                        return
        def left(self):
                if self.download:
                        return
@@ -267,7 +269,7 @@ class NFIDownload(Screen):
                        self.nfo_download()
                if self.focus is self.LIST_DEST:
                        self["destlist"].pageUp()
                        self.nfo_download()
                if self.focus is self.LIST_DEST:
                        self["destlist"].pageUp()
-       
+
        def right(self):
                if self.download:
                        return
        def right(self):
                if self.download:
                        return
@@ -336,7 +338,7 @@ class NFIDownload(Screen):
                        self.download = self.nfo_download
                        self.downloading(True)
                        client.getPage(nfourl).addCallback(self.nfo_finished).addErrback(self.nfo_failed)
                        self.download = self.nfo_download
                        self.downloading(True)
                        client.getPage(nfourl).addCallback(self.nfo_finished).addErrback(self.nfo_failed)
-                       self["statusbar"].text = _("Downloading image description...")
+                       self["statusbar"].text = ("Downloading image description...")
 
        def nfo_failed(self, failure_instance):
                print "[nfo_failed] " + str(failure_instance)
 
        def nfo_failed(self, failure_instance):
                print "[nfo_failed] " + str(failure_instance)
@@ -345,7 +347,7 @@ class NFIDownload(Screen):
                self.nfofilename = ""
                self.nfo = ""
                self.downloading(False)
                self.nfofilename = ""
                self.nfo = ""
                self.downloading(False)
-       
+
        def nfo_finished(self,nfodata=""):
                print "[nfo_finished] " + str(nfodata)
                self.downloading(False)
        def nfo_finished(self,nfodata=""):
                print "[nfo_finished] " + str(nfodata)
                self.downloading(False)
@@ -363,9 +365,9 @@ class NFIDownload(Screen):
                        self.switchList(self.LIST_TARGET)
                if self["feedlist"].isValid():
                        url = self["feedlist"].getNFIurl()
                        self.switchList(self.LIST_TARGET)
                if self["feedlist"].isValid():
                        url = self["feedlist"].getNFIurl()
-                       localfile = self["destlist"].getCurrentDirectory()+'/'+self["feedlist"].getNFIname()
-                       print "[nfi_download] downloading %s to %s" % (url, localfile)
-                       self.download = downloadWithProgress(url,localfile)
+                       self.nfilocal = self["destlist"].getCurrentDirectory()+'/'+self["feedlist"].getNFIname()
+                       print "[nfi_download] downloading %s to %s" % (url, self.nfilocal)
+                       self.download = downloadWithProgress(url,self.nfilocal)
                        self.download.addProgress(self.nfi_progress)
                        self["job_progressbar"].range = 1000
                        self.download.start().addCallback(self.nfi_finished).addErrback(self.nfi_failed)
                        self.download.addProgress(self.nfi_progress)
                        self["job_progressbar"].range = 1000
                        self.download.start().addCallback(self.nfi_finished).addErrback(self.nfi_failed)
@@ -375,7 +377,7 @@ class NFIDownload(Screen):
                #print "[update_progress] recvbytes=%d, totalbytes=%d" % (recvbytes, totalbytes)
                self["job_progressbar"].value = int(1000*recvbytes/float(totalbytes))
                self["job_progresslabel"].text = "%d of %d kBytes (%.2f%%)" % (recvbytes/1024, totalbytes/1024, 100*recvbytes/float(totalbytes))
                #print "[update_progress] recvbytes=%d, totalbytes=%d" % (recvbytes, totalbytes)
                self["job_progressbar"].value = int(1000*recvbytes/float(totalbytes))
                self["job_progresslabel"].text = "%d of %d kBytes (%.2f%%)" % (recvbytes/1024, totalbytes/1024, 100*recvbytes/float(totalbytes))
-       
+
        def nfi_failed(self, failure_instance=None, error_message=""):
                if error_message == "" and failure_instance is not None:
                        error_message = failure_instance.getErrorMessage()
        def nfi_failed(self, failure_instance=None, error_message=""):
                if error_message == "" and failure_instance is not None:
                        error_message = failure_instance.getErrorMessage()
@@ -388,14 +390,6 @@ class NFIDownload(Screen):
                        self.session.open(MessageBox, message, MessageBox.TYPE_ERROR)
                        self.downloading(False)
 
                        self.session.open(MessageBox, message, MessageBox.TYPE_ERROR)
                        self.downloading(False)
 
-       #def nfi_failed(self, failure_instance):
-               #print "[nfi_failed] " 
-               #print failure_instance
-               #if isinstance(failure_instance, Plugins.SystemPlugins.NFIFlash.plugin.UserRequestedCancel):
-                       #print "is instance of Plugins.SystemPlugins.NFIFlash.plugin.UserRequestedCancel"
-               #else:
-                       #print "not an instance of Plugins.SystemPlugins.NFIFlash.plugin.UserRequestedCancel"
-
        def nfi_finished(self, string=""):
                print "[nfi_finished] " + str(string)
                if self.nfo != "":
        def nfi_finished(self, string=""):
                print "[nfi_finished] " + str(string)
                if self.nfo != "":
@@ -406,32 +400,43 @@ class NFIDownload(Screen):
                                nfofd.close()
                        else:
                                print "couldn't save nfo file " + self.nfofilename
                                nfofd.close()
                        else:
                                print "couldn't save nfo file " + self.nfofilename
-       
-                       pos = self.nfo.find("md5sum")
-                       if pos > 0:                                     
-                               self["statusbar"].text = _("Please wait for md5 signature verification...")
-                               cmd = "md5sum -cs " + self.nfofilename
-                               print cmd
+
+                       pos = self.nfo.find("MD5:")
+                       if pos > 0 and len(self.nfo) >= pos+5+32:
+                               self["statusbar"].text = ("Please wait for md5 signature verification...")
+                               cmd = "md5sum -c -"
+                               md5 = self.nfo[pos+5:pos+5+32] + "  " + self.nfilocal
+                               print cmd, md5
                                self.download_container.setCWD(self["destlist"].getCurrentDirectory())
                                self.download_container.setCWD(self["destlist"].getCurrentDirectory())
-                               self.download_container.appClosed.get().append(self.md5finished)
+                               self.download_container.appClosed.append(self.md5finished)
                                self.download_container.execute(cmd)
                                self.download_container.execute(cmd)
+                               self.download_container.write(md5)
+                               self.download_container.dataSent.append(self.md5ready)
                        else:
                                self["statusbar"].text = "Download completed."
                                self.downloading(False)
                else:
                        self["statusbar"].text = "Download completed."
                        self.downloading(False)
                        else:
                                self["statusbar"].text = "Download completed."
                                self.downloading(False)
                else:
                        self["statusbar"].text = "Download completed."
                        self.downloading(False)
+                       if self.wizard_mode:
+                               self.configBackup()
+
+       def md5ready(self, retval):
+               self.download_container.sendEOF()
 
        def md5finished(self, retval):
                print "[md5finished]: " + str(retval)
 
        def md5finished(self, retval):
                print "[md5finished]: " + str(retval)
-               self.download_container.appClosed.get().remove(self.md5finished)
+               self.download_container.appClosed.remove(self.md5finished)
                if retval==0:
                if retval==0:
-                       self["statusbar"].text = _(".NFI file passed md5sum signature check. You can safely flash this image!")
-                       self.switchList(self.LIST_SOURCE)
                        self.downloading(False)
                        self.downloading(False)
+                       if self.wizard_mode:
+                               self.configBackup()
+                       else:
+                               self["statusbar"].text = _(".NFI file passed md5sum signature check. You can safely flash this image!")
+                               self.switchList(self.LIST_SOURCE)
                else:
                        self.session.openWithCallback(self.nfi_remove, MessageBox, (_("The md5sum validation failed, the file may be downloaded incompletely or be corrupted!") + "\n" + _("Remove the broken .NFI file?")), MessageBox.TYPE_YESNO)
                else:
                        self.session.openWithCallback(self.nfi_remove, MessageBox, (_("The md5sum validation failed, the file may be downloaded incompletely or be corrupted!") + "\n" + _("Remove the broken .NFI file?")), MessageBox.TYPE_YESNO)
-       
+
        def nfi_remove(self, answer):
                self.downloading(False)
                if answer == True:
        def nfi_remove(self, answer):
                self.downloading(False)
                if answer == True:
@@ -447,7 +452,7 @@ class NFIDownload(Screen):
                self.imagefilename = "/tmp/nfiflash_" + self.box + ".img"
                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.")
                self.session.openWithCallback(self.flasherdownload_query, MessageBox, (message + '\n' + _("First we need to download the latest boot environment for the USB flasher.")), MessageBox.TYPE_YESNO)
                self.imagefilename = "/tmp/nfiflash_" + self.box + ".img"
                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.")
                self.session.openWithCallback(self.flasherdownload_query, MessageBox, (message + '\n' + _("First we need to download the latest boot environment for the USB flasher.")), MessageBox.TYPE_YESNO)
-               
+
        def flasherdownload_query(self, answer):
                if answer is False:
                        self.downloading(False)
        def flasherdownload_query(self, answer):
                if answer is False:
                        self.downloading(False)
@@ -474,8 +479,8 @@ class NFIDownload(Screen):
        def flasherdownload_finished(self, string=""):
                print "[flasherdownload_finished] " + str(string)       
                self.container = eConsoleAppContainer()
        def flasherdownload_finished(self, string=""):
                print "[flasherdownload_finished] " + str(string)       
                self.container = eConsoleAppContainer()
-               self.container.appClosed.get().append(self.umount_finished)
-               self.container.dataAvail.get().append(self.tool_avail)
+               self.container.appClosed.append(self.umount_finished)
+               self.container.dataAvail.append(self.tool_avail)
                self.taskstring = ""
                umountdevs = ""
                from os import listdir
                self.taskstring = ""
                umountdevs = ""
                from os import listdir
@@ -491,42 +496,31 @@ class NFIDownload(Screen):
                self.taskstring += string
 
        def umount_finished(self, retval):
                self.taskstring += string
 
        def umount_finished(self, retval):
-               self.container.appClosed.get().remove(self.umount_finished)
-               self.session.openWithCallback(self.dmesg_clear, MessageBox, _("To make sure you intend to do this, please remove the target USB stick now and stick it back in upon prompt. Press OK when you have taken the stick out."), MessageBox.TYPE_INFO)
-
-       def dmesg_clear(self, answer):
-               self.container.appClosed.get().append(self.dmesg_cleared)
+               self.container.appClosed.remove(self.umount_finished)
+               self.container.appClosed.append(self.dmesg_cleared)
                self.taskstring = ""
                self.cmd = "dmesg -c"
                print "executing " + self.cmd
                self.container.execute(self.cmd)
                self.taskstring = ""
                self.cmd = "dmesg -c"
                print "executing " + self.cmd
                self.container.execute(self.cmd)
-               
-       def dmesg_cleared(self, retval):
-               self.container.appClosed.get().remove(self.dmesg_cleared)
-               self.session.openWithCallback(self.stick_back_in, MessageBox, (_("Now please insert the USB stick (minimum size is 64 MB) that you want to format and use as .NFI image flasher. Press OK after you've put the stick back in.")), MessageBox.TYPE_INFO)
-
-       def stick_back_in(self, answer):
-               self["statusbar"].text = _("Waiting for USB stick to settle...")
-               self.delayTimer = eTimer()
-               self.delayTimer.callback.append(self.waiting_for_stick)
-               self.delayCount = -1
-               self.delayTimer.start(1000)
-
-       def waiting_for_stick(self):
-               self.delayCount += 1
-               self["job_progressbar"].range = 6
-               self["job_progressbar"].value = self.delayCount
-               self["job_progresslabel"].text = "-%d s" % (6-self.delayCount)
-               if self.delayCount > 5:
-                       self.delayTimer.stop()
-                       self.container.appClosed.get().append(self.dmesg_scanned)
+
+       def dmesg_cleared(self, answer):
+               self.container.appClosed.remove(self.dmesg_cleared)
+               self.msgbox = self.session.open(MessageBox, _("Please disconnect all USB devices from your Dreambox and (re-)attach the target USB stick (minimum size is 64 MB) now!"), MessageBox.TYPE_INFO)
+               hotplugNotifier.append(self.hotplugCB)
+
+       def hotplugCB(self, dev, action):
+               print "[hotplugCB]", dev, action
+               if dev.startswith("sd") and action == "add":
+                       self.msgbox.close()
+                       hotplugNotifier.remove(self.hotplugCB)
+                       self.container.appClosed.append(self.dmesg_scanned)
                        self.taskstring = ""
                        self.cmd = "dmesg"
                        print "executing " + self.cmd
                        self.container.execute(self.cmd)
                        self.taskstring = ""
                        self.cmd = "dmesg"
                        print "executing " + self.cmd
                        self.container.execute(self.cmd)
-               
+
        def dmesg_scanned(self, retval):
        def dmesg_scanned(self, retval):
-               self.container.appClosed.get().remove(self.dmesg_scanned)
+               self.container.appClosed.remove(self.dmesg_scanned)
                dmesg_lines = self.taskstring.splitlines()
                self.devicetext = None
                self.stickdevice = None
                dmesg_lines = self.taskstring.splitlines()
                self.devicetext = None
                self.stickdevice = None
@@ -540,15 +534,15 @@ class NFIDownload(Screen):
                        self.session.openWithCallback(self.remove_img, MessageBox, _("No useable USB stick found"), MessageBox.TYPE_ERROR)
                else:
                        self.session.openWithCallback(self.fdisk_query, MessageBox, (_("The following device was found:\n\n%s\n\nDo you want to write the USB flasher to this stick?") % self.devicetext), MessageBox.TYPE_YESNO)
                        self.session.openWithCallback(self.remove_img, MessageBox, _("No useable USB stick found"), MessageBox.TYPE_ERROR)
                else:
                        self.session.openWithCallback(self.fdisk_query, MessageBox, (_("The following device was found:\n\n%s\n\nDo you want to write the USB flasher to this stick?") % self.devicetext), MessageBox.TYPE_YESNO)
-       
+
        def fdisk_query(self, answer):
        def fdisk_query(self, answer):
-               if answer == True:
-                       self["statusbar"].text = _("Partitioning USB stick...")
+               if answer == True and self.stickdevice:
+                       self["statusbar"].text = ("Partitioning USB stick...")
                        self["job_progressbar"].range = 1000
                        self["job_progressbar"].value = 100
                        self["job_progresslabel"].text = "5.00%"
                        self.taskstring = ""
                        self["job_progressbar"].range = 1000
                        self["job_progressbar"].value = 100
                        self["job_progresslabel"].text = "5.00%"
                        self.taskstring = ""
-                       self.container.appClosed.get().append(self.fdisk_finished)
+                       self.container.appClosed.append(self.fdisk_finished)
                        self.container.execute("fdisk " + self.stickdevice + "/disc")
                        self.container.write("d\nn\np\n1\n\n\nt\n6\nw\n")
                        self.delayTimer = eTimer()
                        self.container.execute("fdisk " + self.stickdevice + "/disc")
                        self.container.write("d\nn\np\n1\n\n\nt\n6\nw\n")
                        self.delayTimer = eTimer()
@@ -558,16 +552,16 @@ class NFIDownload(Screen):
                        self.remove_img(True)
 
        def fdisk_finished(self, retval):
                        self.remove_img(True)
 
        def fdisk_finished(self, retval):
-               self.container.appClosed.get().remove(self.fdisk_finished)
+               self.container.appClosed.remove(self.fdisk_finished)
                self.delayTimer.stop()
                if retval == 0:
                        if fileExists(self.imagefilename):
                                self.tar_finished(0)
                                self["job_progressbar"].value = 700
                        else:
                self.delayTimer.stop()
                if retval == 0:
                        if fileExists(self.imagefilename):
                                self.tar_finished(0)
                                self["job_progressbar"].value = 700
                        else:
-                               self["statusbar"].text = _("Decompressing USB stick flasher boot image...")
+                               self["statusbar"].text = ("Decompressing USB stick flasher boot image...")
                                self.taskstring = ""
                                self.taskstring = ""
-                               self.container.appClosed.get().append(self.tar_finished)
+                               self.container.appClosed.append(self.tar_finished)
                                self.container.setCWD("/tmp")
                                self.cmd = "tar -xjvf nfiflasher_image.tar.bz2"
                                self.container.execute(self.cmd)
                                self.container.setCWD("/tmp")
                                self.cmd = "tar -xjvf nfiflasher_image.tar.bz2"
                                self.container.execute(self.cmd)
@@ -587,13 +581,13 @@ class NFIDownload(Screen):
 
        def tar_finished(self, retval):
                self.delayTimer.stop()
 
        def tar_finished(self, retval):
                self.delayTimer.stop()
-               if len(self.container.appClosed.get()) > 0:
-                       self.container.appClosed.get().remove(self.tar_finished)
+               if len(self.container.appClosed) > 0:
+                       self.container.appClosed.remove(self.tar_finished)
                if retval == 0:
                        self.imagefilename = "/tmp/nfiflash_" + self.box + ".img"
                if retval == 0:
                        self.imagefilename = "/tmp/nfiflash_" + self.box + ".img"
-                       self["statusbar"].text = _("Copying USB flasher boot image to stick...")
+                       self["statusbar"].text = ("Copying USB flasher boot image to stick...")
                        self.taskstring = ""
                        self.taskstring = ""
-                       self.container.appClosed.get().append(self.dd_finished)
+                       self.container.appClosed.append(self.dd_finished)
                        self.cmd = "dd if=%s of=%s" % (self.imagefilename,self.stickdevice+"/part1")
                        self.container.execute(self.cmd)
                        print "executing " + self.cmd
                        self.cmd = "dd if=%s of=%s" % (self.imagefilename,self.stickdevice+"/part1")
                        self.container.execute(self.cmd)
                        print "executing " + self.cmd
@@ -605,14 +599,14 @@ class NFIDownload(Screen):
 
        def dd_finished(self, retval):
                self.delayTimer.stop()
 
        def dd_finished(self, retval):
                self.delayTimer.stop()
-               self.container.appClosed.get().remove(self.dd_finished)
+               self.container.appClosed.remove(self.dd_finished)
                self.downloading(False)
                if retval == 0:
                        self["job_progressbar"].value = 950
                        self["job_progresslabel"].text = "95.00%"
                self.downloading(False)
                if retval == 0:
                        self["job_progressbar"].value = 950
                        self["job_progresslabel"].text = "95.00%"
-                       self["statusbar"].text = _("Remounting stick partition...")
+                       self["statusbar"].text = ("Remounting stick partition...")
                        self.taskstring = ""
                        self.taskstring = ""
-                       self.container.appClosed.get().append(self.mount_finished)
+                       self.container.appClosed.append(self.mount_finished)
                        self.cmd = "mount %s /mnt/usb -o rw,sync" % (self.stickdevice+"/part1")
                        self.container.execute(self.cmd)
                        print "executing " + self.cmd
                        self.cmd = "mount %s /mnt/usb -o rw,sync" % (self.stickdevice+"/part1")
                        self.container.execute(self.cmd)
                        print "executing " + self.cmd
@@ -620,17 +614,18 @@ class NFIDownload(Screen):
                        self.session.openWithCallback(self.remove_img, MessageBox, (self.cmd + " " + _("failed") + ":\n" + str(self.taskstring)), MessageBox.TYPE_ERROR)
 
        def mount_finished(self, retval):
                        self.session.openWithCallback(self.remove_img, MessageBox, (self.cmd + " " + _("failed") + ":\n" + str(self.taskstring)), MessageBox.TYPE_ERROR)
 
        def mount_finished(self, retval):
-               self.container.dataAvail.get().remove(self.tool_avail)
-               self.container.appClosed.get().remove(self.mount_finished)
+               self.container.dataAvail.remove(self.tool_avail)
+               self.container.appClosed.remove(self.mount_finished)
                if retval == 0:
                        self["job_progressbar"].value = 1000
                        self["job_progresslabel"].text = "100.00%"
                if retval == 0:
                        self["job_progressbar"].value = 1000
                        self["job_progresslabel"].text = "100.00%"
-                       self["statusbar"].text = _(".NFI Flasher bootable USB stick successfully created.")
-                       self.session.openWithCallback(self.remove_img, MessageBox, _("The .NFI Image flasher USB stick is now ready to use. Please download an .NFI image file from the feed server and save it on the stick. Then reboot and hold the 'Down' key on the front panel to boot the .NFI flasher from the stick!"), MessageBox.TYPE_INFO)
+                       self["statusbar"].text = (".NFI Flasher bootable USB stick successfully created.")
+                       self.session.openWithCallback(self.flasherFinishedCB, MessageBox, _("The USB stick is now bootable. Do you want to download the latest image from the feed server and save it on the stick?"), type = MessageBox.TYPE_YESNO)
                        self["destlist"].changeDir("/mnt/usb")
                else:
                        self["destlist"].changeDir("/mnt/usb")
                else:
-                       self.session.openWithCallback(self.remove_img, MessageBox, (self.cmd + " " + _("failed") + ":\n" + str(self.taskstring)), MessageBox.TYPE_ERROR)
-       
+                       self.session.openWithCallback(self.flasherFinishedCB, MessageBox, (self.cmd + " " + _("failed") + ":\n" + str(self.taskstring)), MessageBox.TYPE_ERROR)
+                       self.remove_img(True)
+
        def remove_img(self, answer):
                if fileExists("/tmp/nfiflasher_image.tar.bz2"):
                        remove("/tmp/nfiflasher_image.tar.bz2")
        def remove_img(self, answer):
                if fileExists("/tmp/nfiflasher_image.tar.bz2"):
                        remove("/tmp/nfiflasher_image.tar.bz2")
@@ -639,6 +634,43 @@ class NFIDownload(Screen):
                self.downloading(False)
                self.switchList(self.LIST_SOURCE)
 
                self.downloading(False)
                self.switchList(self.LIST_SOURCE)
 
+       def flasherFinishedCB(self, answer):
+               if answer == True:
+                       self.wizard_mode = True
+                       self["feedlist"].moveSelection(0)
+                       self["path_bottom"].text = str(self["destlist"].getCurrentDirectory())
+                       self.nfo_download()
+                       self.nfi_download()
+
+       def configBackup(self):
+               self.session.openWithCallback(self.runBackup, MessageBox, _("The wizard can backup your current settings. Do you want to do a backup now?"))
+
+       def runBackup(self, result=None):
+               from Tools.Directories import createDir, isMount, pathExists
+               from time import localtime
+               from datetime import date
+               from Screens.Console import Console
+               if result:
+                       if isMount("/mnt/usb/"):
+                               if (pathExists("/mnt/usb/backup") == False):
+                                       createDir("/mnt/usb/backup", True)
+                               d = localtime()
+                               dt = date(d.tm_year, d.tm_mon, d.tm_mday)
+                               self.backup_file = "backup/" + str(dt) + "_settings_backup.tar.gz"
+                               self.session.open(Console, title = "Backup running", cmdlist = ["tar -czvf " + "/mnt/usb/" + self.backup_file + " /etc/enigma2/ /etc/network/interfaces /etc/wpa_supplicant.conf"], finishedCallback = self.backup_finished, closeOnSuccess = True)
+               else:
+                       self.backup_file = None
+                       self.backup_finished(skipped=True)
+
+       def backup_finished(self, skipped=False):
+               if not skipped:
+                       wizardfd = open("/mnt/usb/wizard.nfo", "w")
+                       if wizardfd:
+                               wizardfd.write("image: "+self["feedlist"].getNFIname()+'\n')
+                               wizardfd.write("configuration: "+self.backup_file+'\n')
+                               wizardfd.close()
+               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)
+
        def closeCB(self):
                if self.download:
                        self.download.stop()
        def closeCB(self):
                if self.download:
                        self.download.stop()
@@ -662,8 +694,8 @@ def filescan(**kwargs):
                Scanner(mimetypes = ["application/x-dream-image"], 
                        paths_to_scan = 
                                [
                Scanner(mimetypes = ["application/x-dream-image"], 
                        paths_to_scan = 
                                [
-                                       ScanPath(path = "", with_subdirs = False), 
+                                       ScanPath(path = "", with_subdirs = False),
                                ], 
                        name = "NFI", 
                                ], 
                        name = "NFI", 
-                       description = (_("Download .NFI-Files for USB-Flasher")+"..."), 
+                       description = (_("Download .NFI-Files for USB-Flasher")+"..."),
                        openfnc = filescan_open, )
                        openfnc = filescan_open, )