#!/usr/bin/ruby
# encoding: utf-8

require 'MfsTranslator.rb'

class DvdRescueScreen	
	def initialize(extlayers, button, rescuescreen)
		@layers = Array.new
		@extlayers = extlayers 
		@killrescue = false
		@killburn = false
		@imageonly = true
		@isopath = "/tmp/"
		@isoname = "NONAME.iso"
		@imagesize = 0 
		@rescuescreen = rescuescreen
		@lang = ENV['LANGUAGE'][0..1]
		@lang = ENV['LANG'][0..1] if @lang.nil?
		@lang = "en" if @lang.nil?
		# @tlfile = "usbinstall.xml"
		# tlfile = "/usr/share/lesslinux/drivetools/usbinstall.xml" if File.exists?("/usr/share/lesslinux/drivetools/usbinstall.xml")
		# @tl = MfsTranslator.new(@lang, @tlfile)
		### ComboBox for target drives
		@resccombo = Gtk::ComboBox.new
		@rescdrives = Array.new
		@targetcombo = Gtk::ComboBox.new
		@targetparts = Array.new
		@burnercombo = Gtk::ComboBox.new
		@burnerdrives = Array.new
		### ProgressBar for running dd
		@rescueprogress = Gtk::ProgressBar.new
		@killdd = Gtk::Button.new("2. Lauf abbrechen") 
		@killdd.signal_connect("clicked") { 
			system("killall -9 ddrescue")
		} 
		@analyzeprogress = Gtk::ProgressBar.new
		@burnprogress = Gtk::ProgressBar.new
		# attach target screen
		drives = create_drive_screen(extlayers)
		extlayers["dvdrescue"] = drives
		@layers.push drives
		# attach analyze screen
		analyzing = create_analyze_screen(extlayers)
		extlayers["dvdanalyze"] = analyzing
		@layers.push analyzing
		# attach choice screen
		choices = create_choice_screen(extlayers)
		extlayers["dvdchoice"] = choices
		@layers.push choices
		# Attach target screen
		target = create_target_screen(extlayers)
		extlayers["dvdtarget"] = target
		@layers.push target
		# Attach progress screen
		pgscreen = create_progress_screen(extlayers)
		extlayers["dvdprogress"] = pgscreen
		@layers.push pgscreen
		# Attach burners screen
		burningscreen = create_burning_screen(extlayers)
		extlayers["dvdburning"] = burningscreen
		@layers.push burningscreen
		# Attach burners screen
		burnersscreen = create_burner_screen(extlayers)
		extlayers["dvdburners"] = burnersscreen
		@layers.push burnersscreen
		
		button.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				extlayers.each { |k,v|v.hide_all }
				reread_drivelist
				if @rescdrives.size == 1
					extlayers["dvdanalyze"].show_all
					check_source_media(@rescdrives[0])
					extlayers.each { |k,v|v.hide_all }
					if media_is_missing?(@rescdrives[0]) == true 
						TileHelpers.error_dialog("Im Laufwerk wurde kein Datenträger erkannt. Möglicherweise ist die CD/DVD so beschädigt, dass in diesem Laufwerk keine Rettung möglich ist.", "Kein Datenträger erkannt")
						extlayers.each { |k,v|v.hide_all }
						extlayers["start"].show_all
					else
						extlayers.each { |k,v|v.hide_all }
						extlayers["dvdchoice"].show_all
						TileHelpers.error_dialog("Das Inhaltsverzeichnis der CD/DVD ist beschädigt. Wir raten daher dringend, ein Image zu erstellen. Dieses kann später mit Datenrettungsprogrammen untersucht werden.", "Inhaltsverzeichnis beschädigt") if media_is_damaged?(@rescdrives[0]) == true 
					end
				else
					extlayers["dvdrescue"].show_all
				end
			end
		}
	end
	attr_reader :layers
	
	def create_target_screen(extlayers)
		fixed = Gtk::Fixed.new
		TileHelpers.place_back(fixed, extlayers)
		text5 = Gtk::Label.new
		text5.width_request = 250
		text5.wrap = true
		text5.set_markup("<span color='white'>Klicken Sie hier, um die defekte CD/DVD auf das ausgewählte Ziellaufwerk zu kopieren.</span>")
		forw  = Gtk::EventBox.new.add Gtk::Image.new("forward.png")
		tile = Gtk::EventBox.new.add Gtk::Image.new("dvdrescuegreen.png")
		@targetcombo.height_request = 32
		@targetcombo.width_request = 380
		deltext = TileHelpers.create_label("<b>Auswahl des Zwischenspeichers</b>\n\nWählen Sie nun das Ziellaufwerk aus, auf welches das Abbild der defekten CD/DVD kopiert werden soll. Es werden nur Laufwerke mit genügend freiem Platz und geeignetem Dateisystem angezeigt. Das Abbild wird ins Wurzelverzeichnis des Laufwerkes kopiert.", 510)
		reread = Gtk::Button.new("Neu einlesen")
		reread.width_request = 120
		reread.height_request = 32
		reread.signal_connect('clicked') { reread_drivelist }
		forw.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				if @targetparts.size < 1
					TileHelpers.error_dialog("Es wurde kein zur Zwischenspeicherung geeignetes Laufwerk gefunden. Bitte schließen Sie ein USB-Laufwerk mit genügend freiem Speicherplatz an. Klicken Sie auf \"Neu einlesen\".", "Kein geeignetes Laufwerk gefunden")
				else
					@targetparts[@targetcombo.active].mount("rw")
					@isopath = @targetparts[@targetcombo.active].mount_point[0] 
					extlayers.each { |k,v|v.hide_all }
					extlayers["dvdprogress"].show_all
					update_isoname(@rescdrives[@resccombo.active])
					read_dvd(@rescdrives[@resccombo.active])
					if @imageonly == true
						system("sync") 
						if File.exists?("#{@isopath}/#{@isoname}") && TileHelpers.yes_no_dialog("Das Image #{@isoname} wurde erfolgreich erstellt. Wollen Sie nun die Datenrettung auf dem Image starten?", "Abbild erstellt")
							losetup = "losetup /dev/loop23 #{@isopath}/#{@isoname}"
							puts losetup
							system(losetup)
							@rescuescreen.drivelist = @rescuescreen.reread_drivelist(@rescuescreen.drivecombo, false, "loop23" )
							extlayers.each { |k,v| v.hide_all }
							extlayers["photorectypes"].show_all
						else
							@targetparts[@targetcombo.active].umount 
							extlayers.each { |k,v| v.hide_all }
							extlayers["start"].show_all
						end
					else
						reread_burners
						extlayers.each { |k,v|v.hide_all }
						extlayers["dvdburners"].show_all
					end
				end
			end
		}
		fixed.put(tile, 0, 0)
		fixed.put(@targetcombo, 130, 128)
		fixed.put(deltext, 130, 0)
		fixed.put(reread, 520, 128)
		fixed.put(forw, 853, 282)
		fixed.put(text5, 605, 288)
		return fixed
	end
	
	def create_drive_screen(extlayers)
		fixed = Gtk::Fixed.new
		TileHelpers.place_back(fixed, extlayers)
		text5 = Gtk::Label.new
		text5.width_request = 250
		text5.wrap = true
		text5.set_markup("<span color='white'>Klicken Sie hier, um die eingelegte CD/DVD zu analysieren.</span>")
		forw  = Gtk::EventBox.new.add Gtk::Image.new("forward.png")
		tile = Gtk::EventBox.new.add Gtk::Image.new("dvdrescuegreen.png")
		@resccombo.height_request = 32
		@resccombo.width_request = 380
		deltext = TileHelpers.create_label("<b>Auswahl des Quelllaufwerkes</b>\n\nWählen Sie nun das Quelllaufwerk aus, in dem sich die defekte CD oder DVD befindet. Sie können ein USB-Laufwerk anschließen und dann auf \"Neu einlesen\" klicken. Wählen Sie anschließend \"Weiter\", um eine erste Analyse der eingelegten CD/DVD zu starten.", 510)
		reread = Gtk::Button.new("Neu einlesen")
		reread.width_request = 120
		reread.height_request = 32
		reread.signal_connect('clicked') { 
			reread.sensitive = false
			reread_drivelist
			reread.sensitive = true
		}
		forw.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				if @rescdrives.size < 1
					TileHelpers.error_dialog("Es wurde kein zum Lesen geeignetes optisches Laufwerk gefunden. Falls Ihr optisches Laufwerk momentan von der Notfall-DVD benutzt wird, installieren Sie diese auf USB-Speicherstift und starten Sie von diesem. Oder schließen Sie ein USB-DVD-Laufwerk an und klicken Sie auf \"Neu einlesen\".", "Kein optisches Laufwerk gefunden")
				else
					extlayers.each { |k,v| v.hide_all }
					extlayers["dvdanalyze"].show_all
					check_source_media(@rescdrives[@resccombo.active])
					if media_is_missing?(@rescdrives[@resccombo.active]) == true
						TileHelpers.error_dialog("Im Laufwerk wurde kein Datenträger erkannt. Möglicherweise ist die CD/DVD so beschädigt, dass in diesem Laufwerk keine Rettung möglich ist.", "Kein Datenträger erkannt")
						extlayers.each { |k,v| v.hide_all }
						extlayers["dvdrescue"].show_all
					else
						if media_is_damaged?(@rescdrives[@resccombo.active]) == true 
							@imageonly = true
							@imagesize = sizes(@rescdrives[@resccombo.active])[1]
							puts @imagesize.to_s 
							reread_targets
							TileHelpers.error_dialog("Das Inhaltsverzeichnis der CD/DVD ist beschädigt. Es wird nun ein Image der unbeschädigten Sektoren erstellt. Im weiteren Verlauf haben Sie die Möglichkleit, dieses Image auf unbeschädigte Dateien zu untersuchen.", "Inhaltsverzeichnis beschädigt")
							puts "Create image"
							extlayers.each { |k,v|v.hide_all }
							extlayers["dvdtarget"].show_all
						else
							extlayers.each { |k,v| v.hide_all }
							extlayers["dvdchoice"].show_all
						end
					end
				end
			end
		}
		fixed.put(tile, 0, 0)
		fixed.put(@resccombo, 130, 128)
		fixed.put(deltext, 130, 0)
		fixed.put(reread, 520, 128)
		fixed.put(forw, 853, 282)
		fixed.put(text5, 605, 288)
		return fixed
	end
	
	def create_burner_screen(extlayers)
		fixed = Gtk::Fixed.new
		back = TileHelpers.place_back(fixed, extlayers, true)
		text5 = Gtk::Label.new
		text5.width_request = 250
		text5.wrap = true
		text5.set_markup("<span color='white'>Klicken Sie hier, um den Brennvorgang zu starten.</span>")
		forw  = Gtk::EventBox.new.add Gtk::Image.new("forward.png")
		tile = Gtk::EventBox.new.add Gtk::Image.new("dvdrescuegreen.png")
		@burnercombo.height_request = 32
		@burnercombo.width_request = 380
		deltext = TileHelpers.create_label("<b>Auswahl des Brenners</b>\n\nWählen Sie nun den zu verwendenden Brenner aus und legen Sie einen Rohling ein, der dem Quellmedium entspricht. Wurde kein freier Brenner gefunden, können Sie ein USB-Laufwerk anschließen und dann auf \"Neu einlesen\" klicken. Starten Sie anschließend den Brennvorgang.", 510)
		reread = Gtk::Button.new("Neu einlesen")
		reread.width_request = 120
		reread.height_request = 32
		reread.signal_connect('clicked') {
			reread.sensitive = false
			reread_burners
			reread.sensitive = true
		}
		forw.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				if @burnerdrives.size < 1
					TileHelpers.error_dialog("Es wurde kein CD- oder DVD-Brenner gefunden. Falls Ihr Brenner momentan von der Notfall-DVD benutzt wird, installieren Sie diese auf USB-Speicherstift und starten Sie von diesem. Oder schließen Sie einen USB-Brenner an und klicken Sie auf \"Neu einlesen\".", "Kein Brenner gefunden")
				else
					extlayers.each { |k,v| v.hide_all }
					extlayers["dvdburning"].show_all
					burn_iso(@burnerdrives[@burnercombo.active]) 
				end
			end
		}
		fixed.put(tile, 0, 0)
		fixed.put(@burnercombo, 130, 128)
		fixed.put(deltext, 130, 0)
		fixed.put(reread, 520, 128)
		fixed.put(forw, 853, 282)
		fixed.put(text5, 605, 288)
		return fixed
	end
	
	def reread_drivelist
		@killburn = false
		@killrescue = false
		mounted = Array.new
		nicedrives = Array.new
		@rescdrives = Array.new
		100.downto(0) { |i| 
			begin
				@resccombo.remove_text(i) 
			rescue
			end
		}
		IO.popen("cat /proc/mounts") { |l|
			while l.gets
				mounted.push $_.strip.split[0]
			end
		}
		0.upto(9) { |n|
			if File.exists?("/dev/sr#{n.to_s}") &&  File.stat("/dev/sr#{n.to_s}").blockdev?
				@rescdrives.push "sr#{n.to_s}" unless mounted.include?("/dev/sr#{n.to_s}")
			end
		}
		@rescdrives.each { |r|
			model = File.open("/sys/block/#{r}/device/model", "r").read.strip
			vendor = File.open("/sys/block/#{r}/device/vendor", "r").read.strip
			nicedrives.push("#{vendor} #{model} (#{r})") 
		}	
		nicedrives.each { |n| @resccombo.append_text(n) }
		@resccombo.append_text("Kein geeignetes Laufwerk gefunden") if @rescdrives.size < 1 
		@resccombo.active = 0 
		@resccombo.sensitive = false
		@resccombo.sensitive = true if @rescdrives.size > 0
	end
	
	def reread_burners
		mounted = Array.new
		nicedrives = Array.new
		@burnerdrives = Array.new
		100.downto(0) { |i| 
			begin
				@burnercombo.remove_text(i) 
			rescue
			end
		}
		IO.popen("cat /proc/mounts") { |l|
			while l.gets
				mounted.push $_.strip.split[0]
			end
		}
		0.upto(9) { |n|
			if File.exists?("/dev/sr#{n.to_s}") &&  File.stat("/dev/sr#{n.to_s}").blockdev?
				@burnerdrives.push "sr#{n.to_s}" unless mounted.include?("/dev/sr#{n.to_s}") || is_burner?("sr#{n.to_s}") == false
			end
		}
		@burnerdrives.each { |r|
			model = File.open("/sys/block/#{r}/device/model", "r").read.strip
			vendor = File.open("/sys/block/#{r}/device/vendor", "r").read.strip
			nicedrives.push("#{vendor} #{model} (#{r})") 
		}
		nicedrives.each { |n| @burnercombo.append_text(n) }
		@burnercombo.append_text("Kein geeignetes Laufwerk gefunden") if @burnerdrives.size < 1 
		@burnercombo.active = 0 
		@burnercombo.sensitive = false
		@burnercombo.sensitive = true if @burnerdrives.size > 0
	end
	
	def reread_targets
		combobox = @targetcombo
		100.downto(0) { |i| 
			begin
				combobox.remove_text(i) 
			rescue
			end
		}
		TileHelpers.umount_all
		drives = Array.new
		partitions = Array.new
		Dir.entries("/sys/block").each { |l|
			drives.push(MfsDiskDrive.new(l, false)) if l =~ /[a-z]$/ 
		}
		drives.each { |d|
			d.partitions.each  { |p|
				label = label = "#{d.vendor} #{d.model}"
				if d.usb == true
					label = label + " (USB) "
				else
					label = label + " (SATA/eSATA/IDE) "
				end
				label = label + "#{p.device} #{p.human_size}"
				if ( p.fs =~ /vfat/ || p.fs =~ /ntfs/ || p.fs =~ /ext/ || p.fs =~ /btrfs/ ) && p.mount_point.nil? && p.size > ( @imagesize * 110 / 100 )
					if p.fs =~ /vfat/ && @imagesize > 4_294_967_200
						puts "File to large for FAT, skipping"
					elsif  ( @imagesize * 110 / 100 ) > p.free_space 
						puts "File to large for remaining free space, skipping"
					else
						label = label + " #{p.fs}"
						partitions.push p
						combobox.append_text(label)
					end
				end
			}
		}
		combobox.active = 0
		@targetparts = partitions
	end
	
	def create_analyze_screen(extlayers)
		fixed = Gtk::Fixed.new
		tile = Gtk::EventBox.new.add Gtk::Image.new("dvdrescuegreen.png")
		deltext = TileHelpers.create_label("<b>CD/DVD wird analysiert</b>\n\nEs wird eine erste Analyse der CD/DVD durchgeführt, anhand derer eine erste Abschätzung der Beschädigungen möglich ist. Dieser Vorgang dauert weniger als eine Minute.", 510)
		@analyzeprogress.width_request = 510
		@analyzeprogress.height_request = 32
		fixed.put(tile, 0, 0)
		fixed.put(deltext, 130, 0)
		fixed.put(@analyzeprogress, 130, 108)
		return fixed
	end
	
	def create_choice_screen(extlayers)
		fixed = Gtk::Fixed.new
		# First tile, rescue on block level
		button1 = Gtk::EventBox.new.add Gtk::Image.new("dvdrescuewine.png")
		text1 = Gtk::Label.new
		text1.width_request = 380
		text1.wrap = true
		text1.set_markup("<span foreground='white'><b>Image erstellen (empfohlen)</b>\n\nErstellen Sie ein bitgetreues Abbild aller Daten der DVD. Das so erstellte ISO-Image können Sie später mit analysieren oder (bei geringen Beschädigungen) auf einen neuen Rohling brennen. Da der gesamte jemals beschriebene Bereich der CD/DVD ausgelesen wird, ist bei RW-Medien die Rettung versehentlich überschriebener Daten möglich.</span>") 
	
		# Second tile, rescue to cloud
		button2 = Gtk::EventBox.new.add Gtk::Image.new("dvdrescueturq.png")
		text2 = Gtk::Label.new
		text2.width_request = 380
		text2.wrap = true
		text2.set_markup("<span foreground='white'><b>Kopie der CD/DVD erstellen</b>\n\nNur die Daten der aktuell sichtbaren Session werden kopiert und auf einen neuen Rohling geschrieben. Diese Methode wird nur bei leichten Beschädigungen empfohlen.</span>")
		
		fixed.put(button1, 0, 0)
		fixed.put(button2, 0, 130)
		fixed.put(text1, 130, 0)
		fixed.put(text2, 130, 130)
		TileHelpers.place_back(fixed, extlayers)
		
		button1.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				puts "Create image"
				@imageonly = true
				@imagesize = sizes(@rescdrives[@resccombo.active])[1]
				puts @imagesize.to_s 
				reread_targets
				extlayers.each { |k,v|v.hide_all }
				extlayers["dvdtarget"].show_all
			end
		}
		button2.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				puts "Create copy"
				@imageonly = false
				@imagesize = sizes(@rescdrives[@resccombo.active])[0]
				puts @imagesize.to_s 
				extlayers.each { |k,v|v.hide_all }
				if write_to_temp?(@rescdrives[@resccombo.active]) == true
					@isopath = "/tmp/"
					@isoname = "NONAME.iso"
					extlayers["dvdprogress"].show_all
					read_dvd(@rescdrives[@resccombo.active])
					extlayers.each { |k,v|v.hide_all }
					reread_burners
					extlayers["dvdburners"].show_all
				else
					reread_targets
					extlayers["dvdtarget"].show_all
				end
			end
		}
		return fixed
	end
	
	def create_progress_screen(extlayers)
		fixed = Gtk::Fixed.new
		tile = Gtk::EventBox.new.add Gtk::Image.new("dvdrescuegreen.png")
		deltext = TileHelpers.create_label("<b>CD/DVD wird ausgelesen</b>\n\nJe nach Beschädigung und Größe kann das Auslesen mehrere Stunden dauern. Nach dem ersten Durchlauf wird versucht, unlesbare Blöcke erneut einzulesen. Dieser zweite Durchlauf kann abgebrochen werden, wodurch natürlich die Menge der geretteten Daten etwas sinkt.", 510)
		@rescueprogress.width_request = 380
		@rescueprogress.height_request = 32
		@killdd.width_request = 120
		@killdd.height_request = 32
		fixed.put(tile, 0, 0)
		fixed.put(deltext, 130, 0)
		fixed.put(@rescueprogress, 130, 108)
		fixed.put(@killdd, 515, 108)
		# TileHelpers.place_back(fixed, extlayers)
		
		text = Gtk::Label.new
		text.width_request = 250
		text.wrap = true
		text.set_markup("<span color='white'>Klicken Sie hier, um abzubrechen und zum Startbildschirm zurückzukehren.</span>")
		back = Gtk::EventBox.new.add Gtk::Image.new("cancel.png")
		fixed.put(back, 852, 332)
		fixed.put(text, 605, 338)
		back.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				@killrescue = true
				system("killall -9 ddrescue")
				system "rm #{@isopath}/#{@isoname}"
				system("eject /dev/" + @rescdrives[@resccombo.active]) 
				TileHelpers.umount_all 
				extlayers.each { |k,v|v.hide_all }
				extlayers["start"].show_all
				@killrescue = false
			end
		}
		return fixed
	end
	
	def create_burning_screen(extlayers)
		fixed = Gtk::Fixed.new
		tile = Gtk::EventBox.new.add Gtk::Image.new("dvdrescuegreen.png")
		deltext = TileHelpers.create_label("<b>CD/DVD wird gebrannt</b>\n\nEine neue CD/DVD mit den geretteten Daten wird nun gebrannt. Der Brennvorgang dauert je nach Datenmenge und Rohling zwischen einer Minute und drei Stunden.", 510)
		@burnprogress.width_request = 510
		@burnprogress.height_request = 32
		fixed.put(tile, 0, 0)
		fixed.put(deltext, 130, 0)
		fixed.put(@burnprogress, 130, 108)
		back = TileHelpers.place_back(fixed, extlayers, false)
		back.signal_connect('button-release-event') { |x, y|
			if y.button == 1 
				puts "Trying to kill the burn process!"
				@killburn = true
				system("killall xorrecord")
				sleep 0.5
				system("eject /dev/" + @burnerdrives[@burnercombo.active]) 
			end
		}
		return fixed
	end
	
	def burn_iso(device, isofile=nil)
		pgbar = @burnprogress
		command =  ["xorrecord", "--verbose", "dev=/dev/" + device.gsub("/dev/", ""), "blank=as_needed", "-eject", "#{@isopath}/#{@isoname}"  ]
		# TileHelpers.progress(@burnprogress, ["xorrecord", "--verbose", "dev=/dev/" + device.gsub("/dev/", ""), "blank=as_needed", "/tmp/COBIRESCUE.iso"  ], "Brenne neue CD/DVD" )
		# def TileHelpers.progress(pgbar, command, text)
		puts "Running " + command[0] + " : " + command.join(" ")  
		pgbar.text = "Vorbereitung des Brennvorgangs" 
		vte = Vte::Terminal.new
		running = true
		vte.signal_connect("child_exited") { running = false }
		vte.fork_command(command[0], command)
		cycle = 0
		pgbar.fraction = 0.0
		while running == true
			if cycle % 10 == 0
				t = vte.get_text(false)
				lines = t.split("\n")
				puts lines[-2] 
				lines.each { |l|
					if l =~ /\s(\d+)\s+of\s+(\d+).*?written/
						puts $1.to_s + " - " + $2.to_s 
						pgbar.fraction = $1.to_f / $2.to_f
						pgbar.text = "Der Datenträger wird gebrannt"
					end
				}
			end
			# pgbar.pulse
			while (Gtk.events_pending?)
				Gtk.main_iteration
			end
			sleep 0.2 
			cycle += 1 
		end
		pgbar.fraction = 1.0
		lines = vte.get_text(false).split("\n")
		success = false
		lines.each { |l|
			success = true if l =~ /writing to(.*?)completed successfully/i
		}
		if success == true
			TileHelpers.success_dialog("Die CD/DVD wurde erfolgreich gebrannt!", "Brennen abgeschlossen")
			if @isopath =~ /^\/tmp/
				system "rm #{@isopath}/#{@isoname}"
			else
				if TileHelpers.yes_no_dialog("Soll die Image-Datei #{@isoname} gelöscht werden?", "Image löschen?")
					system "rm #{@isopath}/#{@isoname}"
				end
				@targetparts[@targetcombo.active].umount 
			end
			@extlayers.each { |k,v| v.hide_all }
			@extlayers["start"].show_all
		else	
			TileHelpers.error_dialog("Die CD/DVD konnte nicht vollständig gebrannt werden. Mögliche Ursachen sind ein falsches oder beschädigtes Zielmedium oder Abbruch durch den Benutzer!", "Brennen fehlgeschlagen")
			@killburn = false
			@extlayers.each { |k,v| v.hide_all }
			@extlayers["dvdburners"].show_all
		end
	end
	
	def check_source_media(device)
		TileHelpers.progress(@analyzeprogress, ["bash", "xocheckdrive.sh", device.gsub("/dev/", "") ], "Analysiere eingelegte CD/DVD" )
		TileHelpers.progress(@analyzeprogress, ["bash", "xotoc.sh", device.gsub("/dev/", "") ], "Analysiere eingelegte CD/DVD" )
	end
	
	def is_burner?(device)
		TileHelpers.progress(@analyzeprogress, ["bash", "xocheckdrive.sh", device.gsub("/dev/", "") ], "Analysiere eingelegte CD/DVD" )
		return nil unless File.exists?("/var/log/lesslinux/xocheckdrive-#{device}.log")
		File.open("/var/log/lesslinux/xocheckdrive-#{device}.log").each { |line|
			return true if line =~ /supported modes/i
		}
		return false
	end
	
	def sizes(device)
		return nil unless File.exists?("/var/log/lesslinux/xotoc-#{device}.log")
		File.open("/var/log/lesslinux/xotoc-#{device}.log").each { |line|
			if line =~ /media blocks/i 
				puts line 
				data = line.split(":")[1].strip.split 
				min = data[0].to_i * 2048 
				max = data[6].to_i * 2048 
				# puts min.to_s
				# puts max.to_s 
				return [ min, max ] 
			end
		}
		return nil
	end
	
	def media_is_missing?(device)
		return nil unless File.exists?("/var/log/lesslinux/xocheckdrive-#{device}.log")
		File.open("/var/log/lesslinux/xocheckdrive-#{device}.log").each { |line|
			if line =~ /media status/i
				return true if line =~ /not present/i 
			end
		}
		return false
	end
	
	def media_is_damaged?(device)
		return nil unless File.exists?("/var/log/lesslinux/xotoc-#{device}.log")
		File.open("/var/log/lesslinux/xotoc-#{device}.log").each { |line|
			return true if line =~ /read error/i 
		}
		return false
	end
	
	def write_to_temp?(device)
		s = sizes(device)
		return nil if s.nil?
		File.open("/proc/meminfo").each { |line|
			if line =~ /memfree/i
				freemem = line.split[1].to_i * 1024 
				puts line
				puts freemem.to_s 
				if freemem - s[0] >= 268435456
					return true
				else
					return false
				end
			end
		}
		return false 
	end
	
	def update_isoname(device)
		IO.popen("blkid -o udev /dev/#{device}") { |l|
			while l.gets
				ltoks = $_.strip.split("=")
				@isoname = ltoks[1] + ".iso" if ltoks[0] == "ID_FS_LABEL"
			end
		}
	end
	
	def read_dvd(device, target=nil, full=false)
		# FIXME: ask before overwriting!
		system "rm #{@isopath}/#{@isoname}"
		system "rm /var/log/lesslinux/dvdrescue.dd.log"
		@killdd.sensitive = false
		s = sizes(device)
		rescsize = s[0]
		rescsize = s[1] if @imageonly == true 
		@rescueprogress.text = "Erstelle ISO - 1. Lauf, lesbare Blöcke"
		vte = Vte::Terminal.new
		running = true
		vte.signal_connect("child_exited") { running = false }
		vte.fork_command("ddrescue", [ "ddrescue", "-s", rescsize.to_s, "-n", "/dev/#{device}", "#{@isopath}/#{@isoname}", "/var/log/lesslinux/dvdrescue.dd.log" ] )
		cycles = 0 
		@rescueprogress.fraction = 0.0
		while running == true
			if File.exists?("#{@isopath}/#{@isoname}") && cycles % 10  == 0
				fsize = File.size "#{@isopath}/#{@isoname}"
				puts ( ( fsize.to_f / rescsize.to_f ) * 100 ).to_s 
				@rescueprogress.fraction = fsize.to_f / rescsize.to_f
			end
			while (Gtk.events_pending?)
				Gtk.main_iteration
			end
			sleep 0.2 
			cycles += 1 
		end
		return false if @killrescue == true 
		@killdd.sensitive = true
		# start second run
		running = true
		@rescueprogress.text = "Erstelle ISO - 2. Lauf, lese defekte Blöcke"
		vte.fork_command("ddrescue", [ "ddrescue", "-s", rescsize.to_s, "-r", "3", "/dev/#{device}", "#{@isopath}/#{@isoname}", "/var/log/lesslinux/dvdrescue.dd.log" ] )
		while running == true
			@rescueprogress.pulse
			while (Gtk.events_pending?)
				Gtk.main_iteration
			end
			sleep 0.2 
		end
		@rescueprogress.text = "Erstelle ISO - abgeschlossen"
		@rescueprogress.fraction = 1.0
		@killdd.sensitive = false
		system("rm /var/log/lesslinux/dvdrescue.dd.log") 
		system("eject /dev/#{device}")
	end
	
end





