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

require 'time'
require 'net/http'
require 'uri'
require "rexml/document"
require "resolv"

class LicenseScreen

	def initialize(layers, fixed, topbuttons)
		@layers = layers
		@fixed = fixed
		@top_buttons = topbuttons
		@lang = ENV['LANGUAGE'][0..1]
		@lang = ENV['LANG'][0..1] if @lang.nil?
		@lang = "en" if @lang.nil?
		@tl = MfsTranslator.new(@lang, "LicenseScreen.xml") 
		create_first_layer 
	end
	
	def question_dialog(title, text, default=false)
		dialog = Gtk::Dialog.new(
			title,
			$mainwindow,
			Gtk::Dialog::MODAL,
			[ Gtk::Stock::YES, Gtk::Dialog::RESPONSE_YES ],
			[ Gtk::Stock::NO, Gtk::Dialog::RESPONSE_NO ]
		)
		if default == true
			dialog.default_response = Gtk::Dialog::RESPONSE_YES
		else
			dialog.default_response = Gtk::Dialog::RESPONSE_NO
		end
		dialog.has_separator = false
		label = Gtk::Label.new
		label.set_markup(text)
		label.wrap = true
		image = Gtk::Image.new(Gtk::Stock::DIALOG_WARNING, Gtk::IconSize::DIALOG)
		hbox = Gtk::HBox.new(false, 5)
		hbox.border_width = 10
		hbox.pack_start_defaults(image)
		hbox.pack_start_defaults(label)
		dialog.vbox.add(hbox)
		dialog.show_all
		dialog.run { |resp|
			case resp
			when Gtk::Dialog::RESPONSE_YES
				dialog.destroy
				return true
			else
				dialog.destroy
				return false
			end
		}
	end
	
	def info_dialog(title, text) 
		dialog = Gtk::Dialog.new(
			title,
			$mainwindow,
			Gtk::Dialog::MODAL,
			[ Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK ]
		)
		dialog.default_response = Gtk::Dialog::RESPONSE_OK
		dialog.has_separator = false
		label = Gtk::Label.new
		label.set_markup(text)
		label.wrap = true
		image = Gtk::Image.new(Gtk::Stock::DIALOG_INFO, Gtk::IconSize::DIALOG)
		hbox = Gtk::HBox.new(false, 5)
		hbox.border_width = 10
		hbox.pack_start_defaults(image)
		hbox.pack_start_defaults(label)
		dialog.vbox.add(hbox)
		dialog.show_all
		dialog.run { |resp|
			dialog.destroy
			return true
		}
	end
	
	def error_dialog(title, text) 
		dialog = Gtk::Dialog.new(
			title,
			$mainwindow,
			Gtk::Dialog::MODAL,
			[ Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK ]
		)
		dialog.default_response = Gtk::Dialog::RESPONSE_OK
		dialog.has_separator = false
		label = Gtk::Label.new
		label.set_markup(text)
		label.wrap = true
		image = Gtk::Image.new(Gtk::Stock::DIALOG_ERROR, Gtk::IconSize::DIALOG)
		hbox = Gtk::HBox.new(false, 5)
		hbox.border_width = 10
		hbox.pack_start_defaults(image)
		hbox.pack_start_defaults(label)
		dialog.vbox.add(hbox)
		dialog.show_all
		dialog.run { |resp|
			dialog.destroy
			return true
		}
	end
	
	def create_first_layer
		bgimg = Gtk::Image.new("bglicense.png")
		fx = Gtk::Fixed.new
		cancel = Gtk::Button.new(Gtk::Stock::NO) 
		ok = Gtk::Button.new(Gtk::Stock::YES)
		fx.put(bgimg, 0, 0)
		# Label
		infolabel = Gtk::Label.new
		infolabel.wrap = true
		infolabel.width_request = 730
		infolabel.set_markup(@tl.get_translation("license_start"))
		fx.put(infolabel, 35, 70)
		# Text area
		txarea = Gtk::TextView.new
		txarea.wrap_mode = Gtk::TextTag::WRAP_WORD
		eula = "Ooops, no EULA found!"  
		disctext = eula 
		if File.exist?("/etc/lesslinux/secuperts/eula.en.txt")
			disctext = File.new("/etc/lesslinux/secuperts/eula.en.txt").read
		end
		if File.exist?("eula.#{@lang}.txt")
			disctext = File.new("eula.#{@lang}.txt").read
		end
		if File.exist?("/etc/lesslinux/secuperts/eula.#{@lang}.txt")
			disctext = File.new("/etc/lesslinux/secuperts/eula.#{@lang}.txt").read
		end
		txarea.buffer.text = disctext 
		txarea.width_request = 728
		txarea.height_request = 235
		scrolled_win = Gtk::ScrolledWindow.new
		scrolled_win.border_width = 3
		scrolled_win.add(txarea)
		scrolled_win.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS)
		fx.put(scrolled_win, 35, 180)
		# Input field for license key
		liclabel = Gtk::Label.new(@tl.get_translation("license_key")) 
		liclabel.set_markup("<span color='#ffffff'>" +  @tl.get_translation("license_key") + "</span>") 
		liclabel.height_request = 32
		fx.put(liclabel, 35, 430)
		licinput = Gtk::Entry.new
		licinput.text = read_license
		licinput.height_request = 32
		licinput.width_request = 534
		fx.put(licinput, 235, 430)
		# Text to ask if accepted or not
		acclabel = Gtk::Label.new
		acclabel.wrap = true 
		acclabel.width_request = 730
		acclabel.set_markup(@tl.get_translation("do_you_accept")) 
		# fx.put(acclabel, 250, 468)
		[ ok, cancel ].each { |w|
			w.width_request = 128
			w.height_request = 32 
		}
		cancel.signal_connect("clicked") { 
			system("shutdown-wrapper.sh") 
		}
		ok.signal_connect("clicked") { 
			if ( licinput.text.strip.size > 0 && LicenseScreen.offline_check(licinput.text.strip) == true ) || licinput.text.strip.size < 1
				LicenseScreen.online_check(licinput.text.strip) if LicenseScreen.offline_check(licinput.text.strip) == true 
				@layers.each { |k,v| v.hide_all }
				FileUtils.touch("/var/run/lesslinux/license_accepted") 
				FileUtils.mkdir_p("/etc/lesslinux/secuperts")
				unless licinput.text.strip == ""
					# FIXME: quick check first
					lichandle = File.new("/etc/lesslinux/secuperts/license.txt", "w")
					lichandle.write(licinput.text.strip + "\n")
					lichandle.close
				end
				# @layers["start"].show_all 
				# @top_buttons.each { |v| v.show_all }
				exit 0 
			elsif LicenseScreen.offline_check(licinput.text.strip) == false || licinput.text.strip.size < 1
				FileUtils.touch("/var/run/lesslinux/license_accepted") 
				FileUtils.mkdir_p("/etc/lesslinux/secuperts")
				unless File.exist?("/var/run/lesslinux/testperiod")
					tf = File.new("/var/run/lesslinux/testperiod", "w")
					tf.write(Time.now.to_i.to_s)
					tf.close
				end
				testrem = Time.now.to_i + 15 * 24 * 60 * 60 - File.new("/var/run/lesslinux/testperiod").read.to_i 
				error_dialog( @tl.get_translation('invalid_key_title'), @tl.get_translation('invalid_key_text').gsub("REMAINING", testrem.to_s ))
				exit 0
			end
		}
		fx.put(ok, OK_X, OK_Y)
		fx.put(cancel, CANCEL_X, CANCEL_Y)
		@fixed.put(fx, 0, 0)
		@layers["license"] = fx
	end
	
	def read_license
		licfile = "/etc/lesslinux/secuperts/license.txt"
		lictext = ""
		if File.exists? licfile
			lictext = File.new(licfile).read.strip
		end
		return lictext
	end
	
	def LicenseScreen.offline_check(key=nil)
		alphabet = ('a'..'z' ).to_a 
		lictext = key
		if lictext.nil?
			licfile = "/etc/lesslinux/secuperts/license.txt"
			lictext = ""
			if File.exists? licfile
				lictext = File.new(licfile).read.strip
			else
				return false
			end
		end
		outstr = lictext.upcase.strip
		lictext = lictext.gsub(/[^a-zA-Z0-9]/, '').downcase
		return false unless lictext.size == 30
		cs = 0
		0.upto(28) { |c|
			if lictext[c] =~ /[0-9]/ 
				cs += lictext[c].to_i
			else
				cs += alphabet.index(lictext[c]) + 7
			end
		}
		if cs % 10 == lictext[29].to_i
			lichandle = File.new("/etc/lesslinux/secuperts/license.txt", "w")
			lichandle.write(outstr + "\n")
			lichandle.close
			if system("mountpoint /lesslinux/blobpart") 
				FileUtils.mkdir_p("/lesslinux/blobpart/secuperts")
				FileUtils.cp("/etc/lesslinux/secuperts/license.txt", "/lesslinux/blobpart/secuperts")
			end
			return true
		end
		return false 
	end
	
	def LicenseScreen.online_check(key=nil)
		lang = ENV['LANGUAGE'][0..1]
		lang = ENV['LANG'][0..1] if lang.nil?
		lang = "en" if lang.nil?
		@tl = MfsTranslator.new(lang, "LicenseScreen.xml") 
		lictext = key
		licfile = "/etc/lesslinux/secuperts/license.txt"
		if lictext.nil?
			lictext = ""
			if File.exists? licfile
				lictext = File.new(licfile).read.strip
			else
				return false
			end
		end
		# FIXME: Compare license with hardware running on
		# FIXME: Recheck license after three months
		xmlfile =  licfile.gsub("license.txt", "license.xml") 
		hwid = "DVD"
		hwid = LicenseScreen.bios_serial unless LicenseScreen.bios_serial.nil?
		hwid = LicenseScreen.usb_serial unless LicenseScreen.usb_serial.nil?
		
		if File.exists? xmlfile
			return false if LicenseScreen.get_features.nil?
			doc = REXML::Document.new(File.new(xmlfile))
			licensedhw = nil
			begin 
				licensedhw = doc.root.elements["registerSerialResult/LICENSE/HW_ID"].text.strip
			rescue Exception => e
				puts e.message
			end
			begin 
				licensedhw = doc.root.elements["getLicenseResult/LICENSE/HW_ID"].text.strip
			rescue Exception => e
				puts e.message
			end
			return false if licensedhw.nil?			
			return true if licensedhw == hwid
			return false
		end
		
		xmlstr = "<EMRegSys><registerSerial><created>#{Time.now.xmlschema}</created><serial>#{lictext}</serial><hardwareId>#{hwid}</hardwareId><user>test_user</user><setupUpgradeCode>{FA29656A-B5B0-434C-92ED-7D8C612C4209}</setupUpgradeCode></registerSerial></EMRegSys>\n"
		uri =  URI('https://service.engelmann.com/secuperts.php?r=' + URI.escape(xmlstr))
		puts xmlstr
		resp = nil
		begin
			dns = Resolv::DNS.new
			addr = nil
			dns.each_address("service.engelmann.com") { |a| addr = a.to_s }
			http = Net::HTTP.new(addr, uri.port)
			http.read_timeout = 3
			http.open_timeout = 2
			http.use_ssl = true
			http.verify_mode = OpenSSL::SSL::VERIFY_NONE
			resp = http.request(Net::HTTP::Get.new(uri.request_uri))
			xmlanswer = resp.body 
		rescue Exception => e
			puts e.message
			return false
		end
		return false if resp.nil?
		# xmlanswer = Net::HTTP.get(uri)  
		begin
			doc = REXML::Document.new(xmlanswer)
			doc.write($stderr, 4)
		rescue
			return false
		end
		features = LicenseScreen.get_features(doc)
		if features.nil?
			lichandle = File.new("/etc/lesslinux/secuperts/error.xml", "w")
			doc.write(lichandle, 4)
			lichandle.close
			license_exists = false
			errors = Array.new
			doc.root.elements.each("registerSerialResult/ERRORS/ERROR") { |e|
				errors.push e.elements["Message"].text.strip.upcase
				license_exists = true if e.elements["Message"].text.strip.upcase == "E_LICENSE_ALREADY_EXISTS"
			}	
			if license_exists == true
				xmlstr = "<EMRegSys><getLicense><created>#{Time.now.xmlschema}</created><hardwareId>#{hwid}</hardwareId><user>test_user</user><setupUpgradeCode>{FA29656A-B5B0-434C-92ED-7D8C612C4209}</setupUpgradeCode></getLicense></EMRegSys>\n"
				uri =  URI('https://service.engelmann.com/secuperts.php?r=' + URI.escape(xmlstr))
				puts xmlstr
				resp = nil
				begin
					dns = Resolv::DNS.new
					addr = nil
					dns.each_address("service.engelmann.com") { |a| addr = a.to_s }
					http = Net::HTTP.new(addr, uri.port)
					http.read_timeout = 3
					http.open_timeout = 2
					http.use_ssl = true
					http.verify_mode = OpenSSL::SSL::VERIFY_NONE
					resp = http.request(Net::HTTP::Get.new(uri.request_uri))
					xmlanswer = resp.body 
				rescue Exception => e
					puts e.message
					return false
				end
				return false if resp.nil?
				begin
					doc = REXML::Document.new(xmlanswer)
					doc.write($stderr, 4)
				rescue
					return false
				end
				features = LicenseScreen.get_features(doc)
			else
				TileHelpers.error_dialog(@tl.get_translation("key_could_not_be_verified") + errors.join(", "), "Error")
				return false
			end
		end
		lichandle = File.new("/etc/lesslinux/secuperts/license.xml", "w")
		doc.write(lichandle, 4)
		lichandle.close
		if system("mountpoint /lesslinux/blobpart") 
			FileUtils.mkdir_p("/lesslinux/blobpart/secuperts")
			FileUtils.cp("/etc/lesslinux/secuperts/license.xml",  "/lesslinux/blobpart/secuperts")
		end
		return true
	end
	
	def LicenseScreen.get_features(doc=nil)
		features = Array.new
		doc = REXML::Document.new(File.new("/etc/lesslinux/secuperts/license.xml").read) if doc.nil?
		active = false
		begin
			active = true if doc.root.elements["registerSerialResult/LICENSE/STATUS"].text.strip.downcase == "active"
		rescue Exception => e
			puts e.message
		end
		begin 
			active = true if doc.root.elements["getLicenseResult/LICENSE/STATUS"].text.strip.downcase == "active" 
		rescue Exception => e
			puts e.message
		end
		return nil if active == false 
		doc.root.elements.each("registerSerialResult/LICENSE/FEATURES/FEATURE") { |e|
			puts e.elements["NAME"].text.strip
			features.push e.elements["NAME"].text.strip
		}
		doc.root.elements.each("getLicenseResult/LICENSE/FEATURES/FEATURE") { |e|
			puts e.elements["NAME"].text.strip
			features.push e.elements["NAME"].text.strip
		}
		return features 
	end
	
	def LicenseScreen.usb_serial
		scsidev = -1
		hwid = nil
		boot_device = File.new("/var/run/lesslinux/install_source").read.strip 
		if boot_device =~ /^\/dev\/(sd[a-z])[0-9]/
			parent = $1
			if File.directory?("/sys/block/#{parent}/device/scsi_device")
				Dir.entries("/sys/block/#{parent}/device/scsi_device").each { |f|
					scsidev = f.split(":")[0].to_i if  f.split(":")[0].to_i > 0
				}
			end
			if File.exists?("/proc/scsi/usb-storage/#{scsidev}")
				File.open("/proc/scsi/usb-storage/#{scsidev}").each { |l|
					if l.strip =~ /^serial number/i 
						hwid = l.split(": ")[1].strip.gsub("-", "")
					end
				}
			end
		end
		return hwid
	end
	
	def LicenseScreen.bios_serial
		uuid = nil
		IO.popen("dmidecode") { |l|
			while l.gets
				ltoks = $_.strip.split(":")
				uuid = ltoks[1].strip.gsub("-", "") if ltoks[0] =~ /uuid/i
			end
		}
		return uuid 
	end
	
end

