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