Merge branch 'master' of git.opendreambox.org:/git/enigma2
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / NFIFlash / downloader.py
1 from Components.MenuList import MenuList
2 from Screens.Screen import Screen
3 from Screens.MessageBox import MessageBox
4 from Screens.ChoiceBox import ChoiceBox
5 from Components.ActionMap import ActionMap
6 from Components.Sources.StaticText import StaticText
7 from Components.Sources.Progress import Progress
8 from Components.Label import Label
9 from Components.FileList import FileList
10 from Components.MultiContent import MultiContentEntryText
11 from Tools.Directories import fileExists
12 from Tools.HardwareInfo import HardwareInfo
13 from enigma import eConsoleAppContainer, eListbox, gFont, eListboxPythonMultiContent, \
14         RT_HALIGN_LEFT, RT_HALIGN_CENTER, RT_VALIGN_CENTER, RT_WRAP, eRect, eTimer
15 from os import system, remove
16 import re
17 import urllib
18 from twisted.web import client
19 from twisted.internet import reactor, defer
20 from twisted.python import failure
21 from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
22
23 class UserRequestedCancel(Exception):
24         pass
25
26 class HTTPProgressDownloader(client.HTTPDownloader):
27         def __init__(self, url, outfile, headers=None):
28                 client.HTTPDownloader.__init__(self, url, outfile, headers=headers, agent="Dreambox .NFI Download Plugin")
29                 self.status = None
30                 self.progress_callback = None
31                 self.deferred = defer.Deferred()
32
33         def noPage(self, reason):
34                 if self.status == "304":
35                         print reason.getErrorMessage()
36                         client.HTTPDownloader.page(self, "")
37                 else:
38                         client.HTTPDownloader.noPage(self, reason)
39
40         def gotHeaders(self, headers):
41                 if self.status == "200":
42                         if headers.has_key("content-length"):
43                                 self.totalbytes = int(headers["content-length"][0])
44                         else:
45                                 self.totalbytes = 0
46                         self.currentbytes = 0.0
47                 return client.HTTPDownloader.gotHeaders(self, headers)
48
49         def pagePart(self, packet):
50                 if self.status == "200":
51                         self.currentbytes += len(packet)
52                 if self.totalbytes and self.progress_callback:
53                         self.progress_callback(self.currentbytes, self.totalbytes)
54                 return client.HTTPDownloader.pagePart(self, packet)
55
56         def pageEnd(self):
57                 return client.HTTPDownloader.pageEnd(self)
58
59 class downloadWithProgress:
60         def __init__(self, url, outputfile, contextFactory=None, *args, **kwargs):
61                 scheme, host, port, path = client._parse(url)
62                 self.factory = HTTPProgressDownloader(url, outputfile, *args, **kwargs)
63                 self.connection = reactor.connectTCP(host, port, self.factory)
64
65         def start(self):
66                 return self.factory.deferred
67
68         def stop(self):
69                 print "[stop]"
70                 self.connection.disconnect()
71                 #self.factory.deferred.errback(failure.Failure(UserRequestedCancel))
72
73         def addProgress(self, progress_callback):
74                 print "[addProgress]"
75                 self.factory.progress_callback = progress_callback
76
77 class Feedlist(MenuList):
78         def __init__(self, list=[], enableWrapAround = False):
79                 MenuList.__init__(self, list, enableWrapAround, eListboxPythonMultiContent)
80                 self.l.setFont(0, gFont("Regular", 16))
81                 self.l.setItemHeight(22)
82
83         def clear(self):
84                 del self.list[:]
85                 self.l.setList(self.list)
86
87         def getNFIname(self):
88                 l = self.l.getCurrentSelection()
89                 return l and l[0][0]
90
91         def getNFIurl(self):
92                 l = self.l.getCurrentSelection()
93                 return l and l[0][1]
94
95         def getNFOname(self):
96                 l = self.l.getCurrentSelection()
97                 return l and l[0][0][:-3]+"nfo"
98
99         def getNFOurl(self):
100                 l = self.l.getCurrentSelection()
101                 return l and l[0][1][:-3]+"nfo"
102
103         def isValid(self):
104                 l = self.l.getCurrentSelection()
105                 if l[0] == 0:
106                         return False
107                 else:
108                         return True
109
110         def moveSelection(self,idx=0):
111                 if self.instance is not None:
112                         self.instance.moveSelectionTo(idx)
113
114 class NFIDownload(Screen):
115         LIST_SOURCE = 1
116         LIST_DEST = 2
117         skin = """
118                 <screen name="NFIDownload" position="90,95" size="560,420" title="Image download utility">
119                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
120                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
121                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
122                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
123                         <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" />
124                         <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" />
125                         <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" />
126                         <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" />
127                         
128                         <widget source="label_top" render="Label" position="10,44" size="240,20" font="Regular;16" />
129                         <widget name="feedlist" position="10,66" size="250,222" scrollbarMode="showOnDemand" />
130                         <widget name="destlist" position="0,66" size="260,222" scrollbarMode="showOnDemand" />
131
132                         <widget source="label_bottom" render="Label" position="10,312" size="240,18" font="Regular;16"/>
133                         <widget source="path_bottom" render="Label" position="10,330" size="250,42" font="Regular;18" />
134                         
135                         <widget source="infolabel" render="Label" position="270,44" size="280,284" font="Regular;16" />
136                         <widget source="job_progressbar" render="Progress" position="10,374" size="540,26" borderWidth="1" backgroundColor="#254f7497" />
137                         <widget source="job_progresslabel" render="Label" position="130,378" zPosition="2" font="Regular;18" halign="center" transparent="1" size="300,22" foregroundColor="#000000" />
138                         <widget source="statusbar" render="Label" position="10,404" size="540,16" font="Regular;16" foregroundColor="#cccccc" />
139                 </screen>"""
140
141         def __init__(self, session, destdir="/tmp/"):
142                 self.skin = NFIDownload.skin
143                 Screen.__init__(self, session)
144                 
145                 self["job_progressbar"] = Progress()
146                 self["job_progresslabel"] = StaticText()
147                 
148                 self["infolabel"] = StaticText()
149                 self["statusbar"] = StaticText()
150                 self["label_top"] = StaticText()
151                 self["label_bottom"] = StaticText()
152                 self["path_bottom"] = StaticText()
153                 
154                 self["key_green"] = StaticText()
155                 self["key_yellow"] = StaticText()
156                 self["key_blue"] = StaticText()
157
158                 self["key_red"] = StaticText()
159
160                 self["feedlist"] = Feedlist([0,(eListboxPythonMultiContent.TYPE_TEXT, 0, 0,250, 30, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "feed not available")])
161                 self["destlist"] = FileList(destdir, showDirectories = True, showFiles = False)
162                 self["destlist"].hide()
163
164                 self.download_container = eConsoleAppContainer()
165                 self.nfo = ""
166                 self.nfofile = ""
167                 self.feedhtml = ""
168                 self.focus = None
169                 self.download = None
170                 self.box = HardwareInfo().get_device_name()
171                 self.feed_base = "http://www.dreamboxupdate.com/opendreambox/1.5/%s/images/" % self.box
172                 self.nfi_filter = "" # "release" # only show NFIs containing this string, or all if ""
173                 self.wizard_mode = False
174
175                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "DirectionActions", "EPGSelectActions"],
176                 {
177                         "cancel": self.closeCB,
178                         "red": self.closeCB,
179                         "green": self.nfi_download,
180                         "yellow": self.switchList,
181                         "blue": self.askCreateUSBstick,
182                         "prevBouquet": self.switchList,
183                         "nextBouquet": self.switchList,
184                         "ok": self.ok,
185                         "left": self.left,
186                         "right": self.right,
187                         "up": self.up,
188                         "upRepeated": self.up,
189                         "downRepeated": self.down,
190                         "down": self.down
191                 }, -1)
192
193                 self.feed_download()
194
195         def downloading(self, state=True):
196                 if state is True:       
197                         self["key_red"].text = _("Cancel")
198                         self["key_green"].text = ""
199                         self["key_yellow"].text = ""
200                         self["key_blue"].text = ""
201                 else:
202                         self.download = None
203                         self["key_red"].text = _("Exit")
204                         if self["feedlist"].isValid():
205                                 self["key_green"].text = (_("Download"))
206                                 if self.focus is self.LIST_SOURCE:
207                                         self["key_yellow"].text = (_("Change dir."))
208                                 else:
209                                         self["key_yellow"].text = (_("Select image"))
210                         self["key_blue"].text = (_("USB stick wizard"))
211
212         def switchList(self,to_where=None):
213                 if self.download or not self["feedlist"].isValid():
214                         return
215
216                 self["job_progressbar"].value = 0
217                 self["job_progresslabel"].text = ""
218
219                 if to_where is None:
220                         if self.focus is self.LIST_SOURCE:
221                                 to_where = self.LIST_DEST
222                         if self.focus is self.LIST_DEST:
223                                 to_where = self.LIST_SOURCE
224
225                 if to_where is self.LIST_DEST:
226                         self.focus = self.LIST_DEST
227                         self["statusbar"].text = _("Please select target directory or medium")
228                         self["label_top"].text = _("choose destination directory")+":"
229                         self["feedlist"].hide()
230                         self["destlist"].show()
231                         self["label_bottom"].text = _("Selected source image")+":"
232                         self["path_bottom"].text = str(self["feedlist"].getNFIname())
233                         self["key_yellow"].text = (_("Select image"))
234
235                 elif to_where is self.LIST_SOURCE:
236                         self.focus = self.LIST_SOURCE
237                         self["statusbar"].text = _("Please choose .NFI image file from feed server to download")
238                         self["label_top"].text = _("select image from server")+":"
239                         self["feedlist"].show()
240                         self["destlist"].hide()
241                         self["label_bottom"].text = _("Destination directory")+":"
242                         self["path_bottom"].text = str(self["destlist"].getCurrentDirectory())
243                         self["key_yellow"].text = (_("Change dir."))
244
245         def up(self):
246                 if self.download:
247                         return
248                 if self.focus is self.LIST_SOURCE:
249                         self["feedlist"].up()
250                         self.nfo_download()
251                 if self.focus is self.LIST_DEST:
252                         self["destlist"].up()
253
254         def down(self):
255                 if self.download:
256                         return
257                 if self.focus is self.LIST_SOURCE:
258                         self["feedlist"].down()
259                         self.nfo_download()
260                 if self.focus is self.LIST_DEST:
261                         self["destlist"].down()
262
263         def left(self):
264                 if self.download:
265                         return
266                 if self.focus is self.LIST_SOURCE:
267                         self["feedlist"].pageUp()
268                         self.nfo_download()
269                 if self.focus is self.LIST_DEST:
270                         self["destlist"].pageUp()
271
272         def right(self):
273                 if self.download:
274                         return
275                 if self.focus is self.LIST_SOURCE:
276                         self["feedlist"].pageDown()
277                         self.nfo_download()
278                 if self.focus is self.LIST_DEST:
279                         self["destlist"].pageDown()
280
281         def ok(self):
282                 if self.download:
283                         return
284                 if self.focus is self.LIST_DEST:
285                         if self["destlist"].canDescent():
286                                 self["destlist"].descent()
287
288         def feed_download(self):
289                 self.downloading(True)
290                 self.download = self.feed_download
291                 client.getPage(self.feed_base).addCallback(self.feed_finished).addErrback(self.feed_failed)
292
293         def feed_failed(self, failure_instance):
294                 print "[feed_failed] " + str(failure_instance)
295                 self["infolabel"].text = _("Could not connect to Dreambox .NFI Image Feed Server:") + "\n" + failure_instance.getErrorMessage() + "\n\n" + _("Please check your network settings!")
296                 self.downloading(False)
297
298         def feed_finished(self, feedhtml):
299                 print "[feed_finished] " + str(feedhtml)
300                 self.downloading(False)
301                 fileresultmask = re.compile("<a href=[\'\"](?P<url>.*?)[\'\"]>(?P<name>.*?.nfi)</a>", re.DOTALL)
302                 searchresults = fileresultmask.finditer(feedhtml)
303                 fileresultlist = []
304                 if searchresults:
305                         for x in searchresults:
306                                 url = x.group("url")
307                                 if url[0:7] != "http://":
308                                         url = self.feed_base + x.group("url")
309                                 name = x.group("name")
310                                 if name.find(self.nfi_filter) > -1:
311                                         entry = [[name, url],(eListboxPythonMultiContent.TYPE_TEXT, 0, 0,250, 30, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, name)]
312                                         print "adding to feedlist: " + str(entry)
313                                         fileresultlist.append(entry)
314                                 else:
315                                         print "NOT adding to feedlist: " + name
316                         self["feedlist"].l.setList(fileresultlist)
317                         self["feedlist"].moveSelection(0)
318
319                 if len(fileresultlist) > 0:
320                         self.switchList(self.LIST_SOURCE)
321                         self.nfo_download()
322                 else:
323                         self["infolabel"].text = _("Cannot parse feed directory")
324
325         def nfo_download(self):
326                 print "[check_for_NFO]"
327                 if self["feedlist"].isValid():
328                         print "nfiname: " + self["feedlist"].getNFIname()
329                         self["job_progressbar"].value = 0
330                         self["job_progresslabel"].text = ""
331                         if self["feedlist"].getNFIurl() is None:
332                                 self["key_green"].text = ""
333                                 return
334                         self["key_green"].text = _("Download")
335                         nfourl = self["feedlist"].getNFOurl()
336                         print "downloading " + nfourl
337                         self.download = self.nfo_download
338                         self.downloading(True)
339                         client.getPage(nfourl).addCallback(self.nfo_finished).addErrback(self.nfo_failed)
340                         self["statusbar"].text = ("Downloading image description...")
341
342         def nfo_failed(self, failure_instance):
343                 print "[nfo_failed] " + str(failure_instance)
344                 self["infolabel"].text = _("No details for this image file") + "\n" + self["feedlist"].getNFIname()
345                 self["statusbar"].text = ""
346                 self.nfofilename = ""
347                 self.nfo = ""
348                 self.downloading(False)
349
350         def nfo_finished(self,nfodata=""):
351                 print "[nfo_finished] " + str(nfodata)
352                 self.downloading(False)
353                 self.nfo = nfodata
354                 if self.nfo != "":
355                         self.nfofilename = self["destlist"].getCurrentDirectory() + '/' + self["feedlist"].getNFOname()
356                         self["infolabel"].text = self.nfo
357                 else:   
358                         self.nfofilename = ""
359                         self["infolabel"].text = _("No details for this image file")
360                 self["statusbar"].text = ""
361
362         def nfi_download(self):
363                 if self["destlist"].getCurrentDirectory() is None:
364                         self.switchList(self.LIST_TARGET)
365                 if self["feedlist"].isValid():
366                         url = self["feedlist"].getNFIurl()
367                         self.nfilocal = self["destlist"].getCurrentDirectory()+'/'+self["feedlist"].getNFIname()
368                         print "[nfi_download] downloading %s to %s" % (url, self.nfilocal)
369                         self.download = downloadWithProgress(url,self.nfilocal)
370                         self.download.addProgress(self.nfi_progress)
371                         self["job_progressbar"].range = 1000
372                         self.download.start().addCallback(self.nfi_finished).addErrback(self.nfi_failed)
373                         self.downloading(True)
374
375         def nfi_progress(self, recvbytes, totalbytes):
376                 #print "[update_progress] recvbytes=%d, totalbytes=%d" % (recvbytes, totalbytes)
377                 self["job_progressbar"].value = int(1000*recvbytes/float(totalbytes))
378                 self["job_progresslabel"].text = "%d of %d kBytes (%.2f%%)" % (recvbytes/1024, totalbytes/1024, 100*recvbytes/float(totalbytes))
379
380         def nfi_failed(self, failure_instance=None, error_message=""):
381                 if error_message == "" and failure_instance is not None:
382                         error_message = failure_instance.getErrorMessage()
383                 print "[nfi_failed] " + error_message
384                 if fileExists(self["destlist"].getCurrentDirectory()+'/'+self["feedlist"].getNFIname()):
385                         message = "%s %s\n%s" % (_(".NFI Download failed:"), error_message, _("Remove the incomplete .NFI file?"))
386                         self.session.openWithCallback(self.nfi_remove, MessageBox, message, MessageBox.TYPE_YESNO)
387                 else:
388                         message = "%s %s" % (_(".NFI Download failed:"),error_message)
389                         self.session.open(MessageBox, message, MessageBox.TYPE_ERROR)
390                         self.downloading(False)
391
392         def nfi_finished(self, string=""):
393                 print "[nfi_finished] " + str(string)
394                 if self.nfo != "":
395                         self.nfofilename = self["destlist"].getCurrentDirectory() + '/' + self["feedlist"].getNFOname()
396                         nfofd = open(self.nfofilename, "w")
397                         if nfofd:
398                                 nfofd.write(self.nfo)
399                                 nfofd.close()
400                         else:
401                                 print "couldn't save nfo file " + self.nfofilename
402
403                         pos = self.nfo.find("MD5:")
404                         if pos > 0 and len(self.nfo) >= pos+5+32:
405                                 self["statusbar"].text = ("Please wait for md5 signature verification...")
406                                 cmd = "md5sum -c -"
407                                 md5 = self.nfo[pos+5:pos+5+32] + "  " + self.nfilocal
408                                 print cmd, md5
409                                 self.download_container.setCWD(self["destlist"].getCurrentDirectory())
410                                 self.download_container.appClosed.append(self.md5finished)
411                                 self.download_container.execute(cmd)
412                                 self.download_container.write(md5)
413                                 self.download_container.dataSent.append(self.md5ready)
414                         else:
415                                 self["statusbar"].text = "Download completed."
416                                 self.downloading(False)
417                 else:
418                         self["statusbar"].text = "Download completed."
419                         self.downloading(False)
420                         if self.wizard_mode:
421                                 self.configBackup()
422
423         def md5ready(self, retval):
424                 self.download_container.sendEOF()
425
426         def md5finished(self, retval):
427                 print "[md5finished]: " + str(retval)
428                 self.download_container.appClosed.remove(self.md5finished)
429                 if retval==0:
430                         self.downloading(False)
431                         if self.wizard_mode:
432                                 self.configBackup()
433                         else:
434                                 self["statusbar"].text = _(".NFI file passed md5sum signature check. You can safely flash this image!")
435                                 self.switchList(self.LIST_SOURCE)
436                 else:
437                         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)
438
439         def nfi_remove(self, answer):
440                 self.downloading(False)
441                 if answer == True:
442                         nfifilename =  self["destlist"].getCurrentDirectory()+'/'+self["feedlist"].getNFIname()
443                         if fileExists(self.nfofilename):
444                                 remove(self.nfofilename)
445                         if fileExists(nfifilename):
446                                 remove(nfifilename)
447                 self.switchList(self.LIST_SOURCE)
448
449         def askCreateUSBstick(self):
450                 self.downloading()
451                 self.imagefilename = "/tmp/nfiflash_" + self.box + ".img"
452                 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.")
453                 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)
454
455         def flasherdownload_query(self, answer):
456                 if answer is False:
457                         self.downloading(False)
458                         self.switchList(self.LIST_SOURCE)
459                         return
460                 #url = self.feed_base + "/nfiflasher_" + self.box + ".tar.bz2"
461                 url = "http://www.dreamboxupdate.com/download/opendreambox/dreambox-nfiflasher-%s.tar.bz2" % self.box
462                 localfile = "/tmp/nfiflasher_image.tar.bz2"
463                 print "[flasherdownload_query] downloading %s to %s" % (url, localfile)
464                 self["statusbar"].text = ("Downloading %s..." % url)
465                 self.download = downloadWithProgress(url,localfile)
466                 self.download.addProgress(self.nfi_progress)
467                 self["job_progressbar"].range = 1000
468                 self.download.start().addCallback(self.flasherdownload_finished).addErrback(self.flasherdownload_failed)
469
470         def flasherdownload_failed(self, failure_instance=None, error_message=""):
471                 if error_message == "" and failure_instance is not None:
472                         error_message = failure_instance.getErrorMessage()
473                 print "[flasherdownload_failed] " + error_message
474                 message = "%s %s" % (_("Download of USB flasher boot image failed: "),error_message)
475                 self.session.open(MessageBox, message, MessageBox.TYPE_ERROR)
476                 self.remove_img(True)
477
478         def flasherdownload_finished(self, string=""):
479                 print "[flasherdownload_finished] " + str(string)       
480                 self.container = eConsoleAppContainer()
481                 self.container.appClosed.append(self.umount_finished)
482                 self.container.dataAvail.append(self.tool_avail)
483                 self.taskstring = ""
484                 umountdevs = ""
485                 from os import listdir
486                 for device in listdir("/dev"):
487                         if device[:2] == "sd" and device[-1:].isdigit():
488                                 umountdevs += "/dev/"+device
489                 self.cmd = "umount " + umountdevs
490                 print "executing " + self.cmd
491                 self.container.execute(self.cmd)
492
493         def tool_avail(self, string):
494                 print "[tool_avail]" + string
495                 self.taskstring += string
496
497         def umount_finished(self, retval):
498                 self.container.appClosed.remove(self.umount_finished)
499                 self.container.appClosed.append(self.dmesg_cleared)
500                 self.taskstring = ""
501                 self.cmd = "dmesg -c"
502                 print "executing " + self.cmd
503                 self.container.execute(self.cmd)
504
505         def dmesg_cleared(self, answer):
506                 self.container.appClosed.remove(self.dmesg_cleared)
507                 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)
508                 hotplugNotifier.append(self.hotplugCB)
509
510         def hotplugCB(self, dev, action):
511                 print "[hotplugCB]", dev, action
512                 if dev.startswith("sd") and action == "add":
513                         self.msgbox.close()
514                         hotplugNotifier.remove(self.hotplugCB)
515                         self.container.appClosed.append(self.dmesg_scanned)
516                         self.taskstring = ""
517                         self.cmd = "dmesg"
518                         print "executing " + self.cmd
519                         self.container.execute(self.cmd)
520
521         def dmesg_scanned(self, retval):
522                 self.container.appClosed.remove(self.dmesg_scanned)
523                 dmesg_lines = self.taskstring.splitlines()
524                 self.devicetext = None
525                 self.stickdevice = None
526                 for i, line in enumerate(dmesg_lines):
527                         if line.find("usb-storage: waiting for device") != -1 and len(dmesg_lines) > i+3:
528                                 self.devicetext = dmesg_lines[i+1].lstrip()+"\n"+dmesg_lines[i+3]
529                         elif line.find("/dev/scsi/host") != -1:
530                                 self.stickdevice = line.split(":",1)[0].lstrip()
531
532                 if retval != 0 or self.devicetext is None or self.stickdevice is None:
533                         self.session.openWithCallback(self.remove_img, MessageBox, _("No useable USB stick found"), MessageBox.TYPE_ERROR)
534                 else:
535                         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)
536
537         def fdisk_query(self, answer):
538                 if answer == True and self.stickdevice:
539                         self["statusbar"].text = ("Partitioning USB stick...")
540                         self["job_progressbar"].range = 1000
541                         self["job_progressbar"].value = 100
542                         self["job_progresslabel"].text = "5.00%"
543                         self.taskstring = ""
544                         self.container.appClosed.append(self.fdisk_finished)
545                         self.container.execute("fdisk " + self.stickdevice + "/disc")
546                         self.container.write("d\nn\np\n1\n\n\nt\n6\nw\n")
547                         self.delayTimer = eTimer()
548                         self.delayTimer.callback.append(self.progress_increment)
549                         self.delayTimer.start(105, False)
550                 else:
551                         self.remove_img(True)
552
553         def fdisk_finished(self, retval):
554                 self.container.appClosed.remove(self.fdisk_finished)
555                 self.delayTimer.stop()
556                 if retval == 0:
557                         if fileExists(self.imagefilename):
558                                 self.tar_finished(0)
559                                 self["job_progressbar"].value = 700
560                         else:
561                                 self["statusbar"].text = ("Decompressing USB stick flasher boot image...")
562                                 self.taskstring = ""
563                                 self.container.appClosed.append(self.tar_finished)
564                                 self.container.setCWD("/tmp")
565                                 self.cmd = "tar -xjvf nfiflasher_image.tar.bz2"
566                                 self.container.execute(self.cmd)
567                                 print "executing " + self.cmd
568                                 self.delayTimer = eTimer()
569                                 self.delayTimer.callback.append(self.progress_increment)
570                                 self.delayTimer.start(105, False)
571                 else:
572                         print "fdisk failed: " + str(retval)
573                         self.session.openWithCallback(self.remove_img, MessageBox, ("fdisk " + _("failed") + ":\n" + str(self.taskstring)), MessageBox.TYPE_ERROR)
574
575         def progress_increment(self):
576                 newval = int(self["job_progressbar"].value) + 1
577                 if newval < 950:
578                         self["job_progressbar"].value = newval
579                         self["job_progresslabel"].text = "%.2f%%" % (newval/10.0)
580
581         def tar_finished(self, retval):
582                 self.delayTimer.stop()
583                 if len(self.container.appClosed) > 0:
584                         self.container.appClosed.remove(self.tar_finished)
585                 if retval == 0:
586                         self.imagefilename = "/tmp/nfiflash_" + self.box + ".img"
587                         self["statusbar"].text = ("Copying USB flasher boot image to stick...")
588                         self.taskstring = ""
589                         self.container.appClosed.append(self.dd_finished)
590                         self.cmd = "dd if=%s of=%s" % (self.imagefilename,self.stickdevice+"/part1")
591                         self.container.execute(self.cmd)
592                         print "executing " + self.cmd
593                         self.delayTimer = eTimer()
594                         self.delayTimer.callback.append(self.progress_increment)
595                         self.delayTimer.start(105, False)
596                 else:
597                         self.session.openWithCallback(self.remove_img, MessageBox, (self.cmd + " " + _("failed") + ":\n" + str(self.taskstring)), MessageBox.TYPE_ERROR)
598
599         def dd_finished(self, retval):
600                 self.delayTimer.stop()
601                 self.container.appClosed.remove(self.dd_finished)
602                 self.downloading(False)
603                 if retval == 0:
604                         self["job_progressbar"].value = 950
605                         self["job_progresslabel"].text = "95.00%"
606                         self["statusbar"].text = ("Remounting stick partition...")
607                         self.taskstring = ""
608                         self.container.appClosed.append(self.mount_finished)
609                         self.cmd = "mount %s /mnt/usb -o rw,sync" % (self.stickdevice+"/part1")
610                         self.container.execute(self.cmd)
611                         print "executing " + self.cmd
612                 else:
613                         self.session.openWithCallback(self.remove_img, MessageBox, (self.cmd + " " + _("failed") + ":\n" + str(self.taskstring)), MessageBox.TYPE_ERROR)
614
615         def mount_finished(self, retval):
616                 self.container.dataAvail.remove(self.tool_avail)
617                 self.container.appClosed.remove(self.mount_finished)
618                 if retval == 0:
619                         self["job_progressbar"].value = 1000
620                         self["job_progresslabel"].text = "100.00%"
621                         self["statusbar"].text = (".NFI Flasher bootable USB stick successfully created.")
622                         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)
623                         self["destlist"].changeDir("/mnt/usb")
624                 else:
625                         self.session.openWithCallback(self.flasherFinishedCB, MessageBox, (self.cmd + " " + _("failed") + ":\n" + str(self.taskstring)), MessageBox.TYPE_ERROR)
626                         self.remove_img(True)
627
628         def remove_img(self, answer):
629                 if fileExists("/tmp/nfiflasher_image.tar.bz2"):
630                         remove("/tmp/nfiflasher_image.tar.bz2")
631                 if fileExists(self.imagefilename):
632                         remove(self.imagefilename)
633                 self.downloading(False)
634                 self.switchList(self.LIST_SOURCE)
635
636         def flasherFinishedCB(self, answer):
637                 if answer == True:
638                         self.wizard_mode = True
639                         self["feedlist"].moveSelection(0)
640                         self["path_bottom"].text = str(self["destlist"].getCurrentDirectory())
641                         self.nfo_download()
642                         self.nfi_download()
643
644         def configBackup(self):
645                 self.session.openWithCallback(self.runBackup, MessageBox, _("The wizard can backup your current settings. Do you want to do a backup now?"))
646
647         def runBackup(self, result=None):
648                 from Tools.Directories import createDir, isMount, pathExists
649                 from time import localtime
650                 from datetime import date
651                 from Screens.Console import Console
652                 if result:
653                         if isMount("/mnt/usb/"):
654                                 if (pathExists("/mnt/usb/backup") == False):
655                                         createDir("/mnt/usb/backup", True)
656                                 d = localtime()
657                                 dt = date(d.tm_year, d.tm_mon, d.tm_mday)
658                                 self.backup_file = "backup/" + str(dt) + "_settings_backup.tar.gz"
659                                 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)
660
661         def backup_finished(self):
662                 wizardfd = open("/mnt/usb/wizard.nfo", "w")
663                 if wizardfd:
664                         wizardfd.write("image: "+self["feedlist"].getNFIname()+'\n')
665                         wizardfd.write("configuration: "+self.backup_file+'\n')
666                         wizardfd.close()
667                 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)
668
669         def closeCB(self):
670                 if self.download:
671                         self.download.stop()
672                         #self.nfi_failed(None, "Cancelled by user request")
673                         self.downloading(False)
674                 else:
675                         self.close()
676
677 def main(session, **kwargs):
678         session.open(NFIDownload,"/home/root")
679
680 def filescan_open(list, session, **kwargs):
681         dev = "/dev/" + (list[0].path).rsplit('/',1)[0][7:]
682         print "mounting device " + dev + " to /mnt/usb..."
683         system("mount "+dev+" /mnt/usb/ -o rw,sync")
684         session.open(NFIDownload,"/mnt/usb/")
685
686 def filescan(**kwargs):
687         from Components.Scanner import Scanner, ScanPath
688         return \
689                 Scanner(mimetypes = ["application/x-dream-image"], 
690                         paths_to_scan = 
691                                 [
692                                         ScanPath(path = "", with_subdirs = False),
693                                 ], 
694                         name = "NFI", 
695                         description = (_("Download .NFI-Files for USB-Flasher")+"..."),
696                         openfnc = filescan_open, )