Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
#!/usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import generators
from __future__ import division
from __future__ import absolute_import
from __future__ import with_statement
from __future__ import print_function
#
#  Software Feed Plugin by Sven H

plugin_version="0.1-r15"

from Components.ActionMap import ActionMap, HelpableActionMap
from Components.config import config, configfile, ConfigSubsection, ConfigBoolean, ConfigSelection, getConfigListEntry, ConfigDirectory
from Components.ConfigList import ConfigListScreen
from Components.Pixmap import Pixmap
from Components.Label import Label
from Components.Ipkg import IpkgComponent
from Components.ScrollLabel import ScrollLabel
from Tools.LoadPixmap import LoadPixmap
from Screens.Screen import Screen
from Screens.MessageBox import MessageBox
from Screens.ChoiceBox import ChoiceBox
from Screens.HelpMenu import HelpableScreen
from Screens.Standby import TryQuitMainloop
from Components.FileList import FileList
from Components.Sources.StaticText import StaticText
from Components.PluginComponent import PluginComponent, plugins
from enigma import getDesktop, eActionMap, eTimer, eFileWatch, eFileEvent, eConsoleAppContainer, ePoint
from twisted.web.client import getPage
from os import path as os_path, stat as os_stat, remove as os_remove, listdir as os_listdir, kill as os_kill
from re import sub as re_sub, search as re_search
from socket import gethostbyname
from Plugins.Extensions.WebInterface.WebChilds.Toplevel import addExternalChild, externalChildren
from backports import lzma
import Plugins.Extensions.SvenHPlugins.unix_ar as unix_ar
import tarfile
from distutils.version import LooseVersion as Version
import hashlib
import signal
import gzip
from . import _

#get rid of calender import
def abbr_to_num(abbr):
	calendar=[("01","Jan"),("02","Feb"),("03","Mar"),("04","Apr"),("05","May"),("06","Jun"),("07","Jul"),("08","Aug"),("09","Sep"),("10","Oct"),("11","Nov"),("12","Dec")]
	for month in calendar:
		if month[1]==abbr:
			#cprint("Month found: %s %s" % (month[0],month[1]))
			return month[0]

plugin_timeout=5

INSTALLABLE=0
INSTALLED=1
UPDATENEEDED=2
UNINSTALL=3
DOWNGRADE=4

def setConfigSelection(configName, choices, default):
	if not hasattr(config.plugins.svenh,configName):
		#print("set new configSelection")
		setattr(config.plugins.svenh, configName, ConfigSelection(default = default, choices = choices))
	else:
		configEntry = config.plugins.svenh.__getattr__(configName)
		if configEntry.getChoices() != choices:
			#print("change choices", choices)
			configEntry.setChoices(choices = choices, default = default)
		else:
			pass
			#print("nothing to do", choices)

def createConfig():
	yes_no_descriptions = {False: _("no"), True: _("yes")}
	if not hasattr(config.plugins,"svenh"):
		config.plugins.svenh = ConfigSubsection()
	if not hasattr(config.plugins.svenh,"feed"):
		config.plugins.svenh.feed = ConfigBoolean(default = True, descriptions=yes_no_descriptions)
	if not hasattr(config.plugins.svenh,"hide"):
		config.plugins.svenh.hide = ConfigBoolean(default = False, descriptions=yes_no_descriptions)
	if not hasattr(config.plugins.svenh,"version"):
		config.plugins.svenh.version = ConfigBoolean(default = True, descriptions=yes_no_descriptions)
	if not hasattr(config.plugins.svenh,"size"):
		config.plugins.svenh.size = ConfigBoolean(default = False, descriptions=yes_no_descriptions)
	if not hasattr(config.plugins.svenh,"local_user_path"):
		config.plugins.svenh.local_user_path = ConfigDirectory(default = "/")
	if not hasattr(config.plugins.svenh,"show_update_section"):
		config.plugins.svenh.show_update_section = ConfigBoolean(default = True, descriptions=yes_no_descriptions)
	view_options=[]
	#view_options.append(( "false",_("no")))
	view_options.append(( "true",_("Sorting A-Z")))
	view_options.append(( "sort",_("Sorting install state")))
	setConfigSelection(configName = "listview", default = "true", choices = view_options)

	local_options=[]
	local_options.append(( "none",_("no")))
	local_options.append(( "tmp","/tmp"))
	local_options.append(( "data","/data"))
	local_options.append(( "user",_("User defined")))
	setConfigSelection(configName = "local", default = "none", choices = local_options)

	confirm_options=[]
	confirm_options.append(( "false",_("no")))
	confirm_options.append(( "true",_("yes")))
	confirm_options.append(( "info",_("Message")))
	setConfigSelection(configName = "confirm", choices = confirm_options, default = "true")
	
	info_options=[]
	info_options.append(( "name",_("Name")))
	info_options.append(( "desc",_("Description")))
	setConfigSelection(configName = "show_info", choices = info_options, default = "desc")

	# dummy configs ...
	if not hasattr(config.plugins.svenh,"package_install"):
		plugin_options_install=[]
		plugin_options_install.append(( "install1",_("Installation available")))
		plugin_options_install.append(( "install2",_("Installation available")))
		config.plugins.svenh.package_install = ConfigSelection(default = "install1", choices=plugin_options_install)
	if not hasattr(config.plugins.svenh,"package_uninstall"):
		plugin_options_uninstall=[]
		plugin_options_uninstall.append(( "uninstall1",_("Installation finished")))
		plugin_options_uninstall.append(( "uninstall2",_("Installation finished")))
		config.plugins.svenh.package_uninstall = ConfigSelection(default = "uninstall1", choices=plugin_options_uninstall)
	if not hasattr(config.plugins.svenh,"package_update"):
		plugin_options_update=[]
		plugin_options_update.append(( "update1",_("Update available")))
		plugin_options_update.append(( "update2",_("Update available")))
		config.plugins.svenh.package_update = ConfigSelection(default = "update1", choices=plugin_options_update)
	if not hasattr(config.plugins.svenh,"package_downgrade"):
		plugin_options_downgrade=[]
		plugin_options_downgrade.append(( "downgrade1",_("Downgrade")))
		plugin_options_downgrade.append(( "downgrade2",_("Downgrade")))
		config.plugins.svenh.package_downgrade = ConfigSelection(default = "downgrade1", choices=plugin_options_downgrade)
	if not hasattr(config.plugins.svenh,"package_empty"):
		plugin_options_empty=[]
		plugin_options_empty.append(( "empty1"," "))
		plugin_options_empty.append(( "empty2"," "))
		config.plugins.svenh.package_empty = ConfigSelection(default = "empty1", choices=plugin_options_empty)
	return

def cprint(text):
	print("[SvenHPlugins] " + text)

def audio2Help():
	cprint("AUDIO pressed")
	#Device Types
	TYPE_STANDARD = "dreambox remote control (native)"
	TYPE_ADVANCED = "dreambox advanced remote control (native)"
	TYPE_KEYBOARD = "dreambox ir keyboard"
	#Advanced remote or standard?
	if config.misc.rcused.value == 0:
		remotetype = TYPE_ADVANCED
	else:
		remotetype = TYPE_STANDARD
	eam = eActionMap.getInstance()
	# press the key with the desired flag
	keycode=138 # HELP key
	cprint("NOW WRITES OUT: %i = HELP" % (keycode))
	eam.keyPressed(remotetype, keycode, 0)
	# release the key
	eam.keyPressed(remotetype, keycode, 1)

createConfig() # check inside ...

plugin_status_file="/var/lib/dpkg/status"
plugindir="/usr/lib/enigma2/python/Plugins/Extensions/SvenHPlugins"
plugin_log="/tmp/svenhPlugins.log"
plugin_feedlist="/etc/apt/sources.list.d/svenh-feed.list"
plugin_feedName = "svenh-feed"
feedPlugin_PackageName = "enigma2-plugin-extensions-svenhfeedplugin"
statusfile_data = ""

def getTitle():
	feed = "Sven H - " + _("Feed Plugin")
	return feed

def getFeedUrl():
	feedurl = "deb [trusted=yes] https://apt.fury.io/%s/ ./\n" % plugin_feedName
	cprint("getFeedUrl: %s" % feedurl)
	return feedurl

def getPackages(feed=""):
	packages_file = "/var/lib/apt/lists/apt.fury.io_%s_._Packages" % (plugin_feedName)
	cprint("get packages file: %s" % packages_file)
	return packages_file

def getPackagesList(getAll=False):
	packagesList=[]
	packagesList.append(getPackages())
	return packagesList

def sortPackages(packages):
	cprint(">>>> sortPackages")
	try:
		sort_packages = []
		for package in packages:
			package_list = package.strip("\n").split("\n")
			package = dict([(x.split(":")[0].strip(),x.split(":")[1].strip()) for x in package_list])
			desc=package['Description'].split(",")
			sp=desc[0].split(" ")
			print(sp)
			if len(sp)>1:
				name="%s %s" % (sp[0],sp[1])
			else:
				name="%s" % (sp[0])
			package['PackageName'] = name
			sort_packages.append(package)
		sort_packages = sorted(sort_packages, key=lambda k: k['PackageName'].lower())
		return sort_packages
	except:
		import traceback, sys
		traceback.print_exc()
		return ""

sz_w = getDesktop(0).size().width()

gheader = " " * 6
gtrailer = ""

def getArch():
	boxtype="dreamone"
	if os_path.exists("/proc/stb/info/model"):
		f=open("/proc/stb/info/model")
		boxtype=f.read()
		f.close()
		boxtype=boxtype.replace("\n","").replace("\l","")
	if boxtype == "dm525":
		boxtype="dm520"
	if boxtype == "one":
		boxtype="dreamone"
	if boxtype == "two":
		boxtype="dreamtwo"
	arch="arm64"
	if boxtype=="dm900" or boxtype=="dm920":
		arch="armhf"
	if boxtype=="dm7080" or boxtype=="dm820" or boxtype=="dm520":
		arch="mipsel"
	return arch

def addFeed(update=True):
	cprint("ADDING FEED")
	feedurl=getFeedUrl()
	packages=getPackages()
	if not os_path.exists(plugin_feedlist):
		f=open(plugin_feedlist,"w")
		f.write(feedurl)
		f.close()
	else:
		f=open(plugin_feedlist,"r")
		feed=f.read()
		f.close()
		if feed!=feedurl:
			f=open(plugin_feedlist,"w")
			f.write(feedurl)
			f.close()
	if os_path.exists(packages):
		metaDreamy(True)
	if update:
		aptUpdate()

def removeFeed():
	cprint("REMOVING FEED")
	if os_path.exists(plugin_feedlist):
		os_remove(plugin_feedlist)
	metaDreamy(False)
	
	packagesList = getPackagesList()
	for package in packagesList:
		if os_path.exists(package):
			cprint("remove packages file: %s" % package)
			os_remove(package)

def aptUpdate():
	cprint("apt-get update")
	ipkg = IpkgComponent()
	ipkg.startCmd(IpkgComponent.CMD_UPDATE)

def checkCompression(file_start):
	compressed_magic_dict = { "\x1f\x8b\x08": "gz", "\xfd\x37\x7a": "xz" }
	hex_start=":".join("{:02x}".format(ord(c)) for c in file_start)
	for magic, filetype in compressed_magic_dict.items():
		if file_start.startswith(str(magic)):
			cprint("COMPRESSION %s %s" % (filetype, hex_start[:6]))
			return filetype
	cprint("COMPRESSION UNKNOWN %s" % (hex_start[:6]))
	return "unknown"

def parseControl(controlstr):
	control=controlstr.split("\n")
	name="none"
	desc=[]
	status=INSTALLABLE
	new=""
	depends=[]
	deb=""
	line="none"
	package=False
	for line in control:
		if package:
			# cprint(">>>>>> %s" % line)
			if line.startswith("Description:"):
				sp=line.split(":")
				if len(sp) > 1:
					dd=sp[1].strip()
					sp=dd.split(" ")
					ll=len(sp)
					if ll > 5: # name shows maximum 5 words
						ll=5
					i=1
					name=sp[0]
					while i < ll:
						name="%s %s" % (name,sp[i])
						i+=1
					# cprint(">>>>>> Description: %s" % name)
			if line.startswith("Version:"):
				sp=line.split(":")
				if len(sp) > 1:
					new=sp[1].strip()
					# cprint(">>>>>> Version: %s" % new)
			if line.startswith("Depends:"):
				sp=line.split(":")
				if len(sp) > 1:
					depends=sp[1].split(",")
					# cprint(">>>>>> Depends: %s" % depends)
			if line.startswith(("\t"," ")):
				desc.append(line.lstrip("\t").lstrip(" ").rstrip("\n"))
				# cprint(">>>>>> Description: %s" % desc)
		if line.find("Package:") != -1:
			package=True
			sp=line.split(":")
			if len(sp) > 1:
				# cprint(">>>>>> Package: %s" % sp[1])
				deb=sp[1].strip()
		# this has to come to an end ...
		if line.find("postinst") != -1 or line.find("postrm") != -1 or line.find("preinst") != -1 or line.find("prerm") != -1:
			package=False
	return (name,desc,deb,status,new,depends)

def parseDoc(directory, file):
	sp=file.split("_")
	kit=sp[0]
	cprint(kit)
	f=open(directory+"/"+file,"r")
	header = f.read(32)
	changelog=""
	readme=""
	copyright=""
	if header[:7] != "!<arch>":
		cprint("WRONG HEADER %s" % header[:7])
		f.close()
		return (changelog,copyright,readme)
	#cprint("%s has ar file format" % file)
	f.seek(0)
	debian=f.read(1024*50) # 50kB should be enought for debian.tar
	f.close()
	ar_file=unix_ar.open(directory+"/"+file)
	if debian.find("data.tar.gz/") != -1:
		#cprint("data.tar.gz/")
		data_tar=ar_file.open("data.tar.gz/")
	elif debian.find("data.tar.gz") != -1:
		#cprint("data.tar.gz")
		data_tar=ar_file.open("data.tar.gz")
	elif debian.find("data.tar.xz/") != -1:
		#cprint("data.tar.xz/")
		data_tar=ar_file.open("data.tar.xz/")
		data=data_tar.read()
		uncomp=lzma.decompress(data)
		c=open("/tmp/data.tar","w")
		c.write(uncomp)
		c.close()
		data_tar.close()
		data_tar=open("/tmp/data.tar")
	elif debian.find("data.tar.xz") != -1:
		#cprint("data.tar.xz")
		# python 2.7 tarfile has no xz support
		data_tar=ar_file.open("data.tar.xz")
		data=data_tar.read()
		uncomp=lzma.decompress(data)
		c=open("/tmp/data.tar","w")
		c.write(uncomp)
		c.close()
		data_tar.close()
		data_tar=open("/tmp/data.tar")
	else:
		cprint("STRANGE data")
		del debian
		data_tar.close()
		return (changelog,copyright,readme)
	del debian
	data=tarfile.open(fileobj=data_tar)
	found=False
	try:
		dtr=data.extractfile("./usr/share/doc/%s/copyright" % kit)
		copyright=dtr.read()
		dtr.close()
	except:
		pass
	try:
		dtr=data.extractfile("./usr/share/doc/%s/README" % kit)
		readme=dtr.read()
		dtr.close()
	except:
		pass
	if len(readme)==0:
		try:
			dtr=data.extractfile("./usr/share/doc/%s/README.Debian" % kit)
			readme=dtr.read()
			dtr.close()
		except:
			pass
	try:
		dtr=data.extractfile("./usr/share/doc/%s/changelog" % kit)
		changelog=dtr.read()
		dtr.close()
	except:
		pass
	if len(changelog)==0:
		try:
			dtr=data.extractfile("./usr/share/doc/%s/changelog.gz" % kit)
			changelog=dtr.read()
			dtr.close()
			# gzip.decompress not yet in python 2.7
			f=open("/tmp/changelog.gz","w")
			f.write(changelog)
			f.close()
			f=gzip.open("/tmp/changelog.gz","r")
			changelog=f.read()
			f.close()
		except:
			pass
	if len(changelog)==0:
		try:
			dtr=data.extractfile("./usr/share/doc/%s/changelog.Debian.gz" % kit)
			changelog=dtr.read()
			dtr.close()
			# gzip.decompress not yet in python 2.7
			f=open("/tmp/changelog.gz","w")
			f.write(changelog)
			f.close()
			f=gzip.open("/tmp/changelog.gz","r")
			changelog=f.read()
			f.close()
		except:
			pass
	#
	# here we should add further variants of filenames
	# ....
	data.close()
	data_tar.close()
	return (changelog,copyright,readme)

def parseDeb(directory, file):
	# FALLBACK for failed control parsing from deb filename
	md5sums=""
	ff=file.split("_")
	deb=ff[0]
	nn=deb.split("-")
	name=nn[-1]
	desc=name
	boxkit="_"+getArch()+".deb"
	if len(ff) > 1:
		new=ff[1].replace("_all.deb","").replace(boxkit,"")
	else:
		new=_("unknown")
	status=INSTALLABLE
	depends=[]
	arendchar=chr(0x60)+chr(0x0A)
	f=open(directory+"/"+file,"r")
	header = f.read(32)
	if header[:7] != "!<arch>":
		print("WRONG HEADER %s" % header[:7])
		f.close()
		return (name,desc,deb,status,new,depends,md5sums)
	#cprint("%s has ar file format" % file)
	f.seek(0)
	debian=f.read(1024*50) # 20kB should be enought for control.tar
	f.close()
	ar_file=unix_ar.open(directory+"/"+file)
	if debian.find("control.tar.gz/") != -1:
		control_tar=ar_file.open("control.tar.gz/")
	elif debian.find("control.tar.gz") != -1:
		control_tar=ar_file.open("control.tar.gz")
	elif debian.find("control.tar.xz/") != -1:
		control_tar=ar_file.open("control.tar.xz/")
		control=control_tar.read()
		uncomp=lzma.decompress(control)
		c=open("/tmp/control.tar","w")
		c.write(uncomp)
		c.close()
		control_tar.close()
		control_tar=open("/tmp/control.tar")
	elif debian.find("control.tar.xz") != -1:
		# python 2.7 tarfile has no xz support
		control_tar=ar_file.open("control.tar.xz")
		control=control_tar.read()
		uncomp=lzma.decompress(control)
		c=open("/tmp/control.tar","w")
		c.write(uncomp)
		c.close()
		control_tar.close()
		control_tar=open("/tmp/control.tar")
	else:
		cprint("STRANGE control")
		del debian
		return (name,desc,deb,status,new,depends,md5sums)
	del debian
	control=tarfile.open(fileobj=control_tar)
	ctrl=control.extractfile("./control")
	control_content=ctrl.read()
	ctrl.close()
	try:
		md5=control.extractfile("./md5sums")
		md5sums=md5.read()
		md5.close()
		cprint("%s with MD5SUM: %s" % (file,md5sums))
	except:
		pass
	control.close()
	control_tar.close()
	name,desc,deb,status,new,depends=parseControl(control_content)
	return (name,desc,deb,status,new,depends,md5sums)

plugin_skin=config.skin.primary_skin.value.replace("/skin.xml","")

def getPiconPath(name):
	if os_path.exists("/usr/share/enigma2/%s/skin_default/%s.svg" % (plugin_skin,name)):
		return "/usr/share/enigma2/%s/skin_default/%s.svg" % (plugin_skin,name)
	if os_path.exists("/usr/share/enigma2/%s/skin_default/%s.png" % (plugin_skin,name)):
		return "/usr/share/enigma2/%s/skin_default/%s.png" % (plugin_skin,name)
	if os_path.exists("/usr/share/enigma2/%s/skin_default/icons/%s.png" % (plugin_skin,name)):
		return "/usr/share/enigma2/%s/skin_default/icons/%s.png" % (plugin_skin,name)
	if os_path.exists("/usr/share/enigma2/%s/skin_default/icons/%s.svg" % (plugin_skin,name)):
		return "/usr/share/enigma2/%s/skin_default/icons/%s.svg" % (plugin_skin,name)
	if os_path.exists("/usr/share/enigma2/skin_default/%s.svg" % (name)):
		return "/usr/share/enigma2/skin_default/%s.svg" % (name)
	if os_path.exists("/usr/share/enigma2/skin_default/icons/%s.png" % (name)):
		return "/usr/share/enigma2/skin_default/icons/%s.png" % (name)
	if os_path.exists("/usr/share/enigma2/skin_default/buttons/key_%s.png" % (name)):
		return "/usr/share/enigma2/skin_default/buttons/key_%s.png" % (name)
	return "/usr/share/enigma2/skin_default/%s.png" % (name)

class Console(Screen):
	skin = """
			<screen position="100,100" size="550,400" title="Command execution..." >
					<widget name="text" position="0,0" size="550,400" font="Console;14" />
			</screen>"""

	def __init__(self, session, title = "Console", cmdlist = None, finishedCallback = None, closeOnSuccess = False, logfile = None, start_text=""):
		Screen.__init__(self, session)

		self.finishedCallback = finishedCallback
		self.closeOnSuccess = closeOnSuccess

		self["text"] = ScrollLabel("")
		self["actions"] = ActionMap(["WizardActions", "DirectionActions"],
		{
				"ok": self.cancel,
				"back": self.cancel,
				"up": self["text"].pageUp,
				"down": self["text"].pageDown
		}, -1)

		self.cmdlist = cmdlist
		self.newtitle = title
		self.logfile = logfile
		self.start_text = start_text

		self.onShown.append(self.updateTitle)

		self.container = eConsoleAppContainer()
		self.run = 0
		self.appClosed_conn = self.container.appClosed.connect(self.runFinished)
		self.dataAvail_conn = self.container.dataAvail.connect(self.dataAvail)
		self.onLayoutFinish.append(self.startRun) # dont start before gui is finished

	def updateTitle(self):
		self.setTitle(self.newtitle)

	def startRun(self):
		if self.start_text:
			self["text"].setText(_("Execution Progress:") + "\n\n" + self.start_text + "\n\n")
		else:
			self["text"].setText(_("Execution Progress:") + "\n\n")
		if not self.logfile is None:
			if os_path.exists(self.logfile):
				os_remove(self.logfile)
			self.output=open(self.logfile,"w")
		cprint("console: executing in run %s the command: %s" % (self.run, self.cmdlist[self.run]))
		self.last_str = ""
		if self.container.execute(self.cmdlist[self.run]): #start of container application failed...
			self.runFinished(-1) # so we must call runFinished manual

	def runFinished(self, retval):
		self.run += 1
		if self.run != len(self.cmdlist):
			if self.container.execute(self.cmdlist[self.run]): #start of container application failed...
				self.runFinished(-1) # so we must call runFinished manual
		else:
			str = self["text"].getText().rstrip("\n")
			str += "\n\n" + _("Execution finished!!");
			self["text"].setText(str)
			self["text"].lastPage()
			if not self.finishedCallback is None:
				self.finishedCallback()
			if not retval and self.closeOnSuccess:
				self.cancel()

	def cancel(self):
		if self.run == len(self.cmdlist):
			if not self.logfile is None:
				self.output.close()
			self.close()
			self.appClosed_conn = None
			self.dataAvail_conn = None

	def dataAvail(self, str):
		out_str = ""
		#print(">>> dataAvail str", str)
		for char in str:
			#print(">>> char", char, ord(char))
			self.last_str += char
			if len(self.last_str)>1 and ord(char)==10:
				#print(">>> dataAvail last_str", self.last_str)
				if self.last_str.startswith("W: Size of file") \
				or self.last_str == "Reading package lists...\n" \
				or self.last_str == "Building dependency tree...\n" \
				or self.last_str == "Reading state information...\n" \
				or self.last_str.startswith("0 upgraded, 0 newly installed"):
					#print(">>> dataAvail remove", self.last_str)
					self.last_str = ""
				else:
					self.last_str = re_sub('W: Size of file.*server reported \d* \d*', '', self.last_str)
					self.last_str = self.last_str.replace('Reading state information...\n', '')
					out_str += self.last_str # save str to write in console
					self.last_str = ""

		if out_str:
			#print(">>> dataAvail write", out_str)
			self["text"].setText(self["text"].getText() + out_str)
			if not self.logfile is None:
				self.output.write(out_str)


	def dataAvail_old(self, str):
		if str == "\n" and self.last_str_remove:
			return
		self.last_str_remove = True
		if str.startswith("W: Size of file") or str in ("W", "W:", ": "):
			#print(">>> remove in dataAvail '%s'" % str)
			return
		if str.find("is not what the server reported") != -1:
			#print(">>> remove in dataAvail '%s'" % str)
			return
		if "Reading package lists..." in str or "Building dependency tree..." in str or "Reading state information..." in str:
			#print(">>> remove in dataAvail '%s'" % str)
			return
		if str.startswith("0 upgraded, 0 newly installed"):
			#print(">>> remove in dataAvail '%s'" % str)
			return

		self.last_str_remove = False
		#print(">>> write in dataAvail '%s'" % str)
		self["text"].setText(self["text"].getText() + str)
		if not self.logfile is None:
			self.output.write(str)

class SvenH_Main(Screen, ConfigListScreen, HelpableScreen):
	if sz_w == 1920:
		skin = """
		<screen name="SvenH_Main" position="center,170" size="1200,890">
		<widget name="logo" position="20,10" size="150,60" />
		<widget backgroundColor="#9f1313" font="Regular;26" halign="center" name="buttonred" position="180,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget backgroundColor="#1f771f" font="Regular;26" halign="center" name="buttongreen" position="370,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget backgroundColor="#a08500" font="Regular;26" halign="center" name="buttonyellow" position="560,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget backgroundColor="#18188b" font="Regular;26" halign="center" name="buttonblue" position="750,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget name="gemfury" position="1002,12" size="177,56" alphatest="on" />
		<widget name="info" position="935,10" size="60,30" alphatest="on" />
		<widget name="menu" position="935,40" size="60,30" alphatest="on" />
		<eLabel backgroundColor="grey" position="20,90" size="1160,1" />
		<widget name="config" enableWrapAround="1" position="30,110" scrollbarMode="showOnDemand" size="1140,720" />
		<eLabel backgroundColor="grey" position="20,840" size="1160,1" />
		<widget name="text" foregroundColor="white" backgroundColor="background" position="30,850" size="1100,35" font="Regular;26" zPosition="1" halign="center" valign="center" transparent="0"/>
		</screen>"""
	elif sz_w == 2560:
		skin = """
		<screen name="SvenH_Main" position="center,200" size="1640,1160" >
		<widget name="logo" position="20,10" size="200,80" />
		<widget backgroundColor="#9f1313" font="Regular;32" halign="center" name="buttonred" position="230,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget backgroundColor="#1f771f" font="Regular;32" halign="center" name="buttongreen" position="490,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget backgroundColor="#a08500" font="Regular;32" halign="center" name="buttonyellow" position="750,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget backgroundColor="#18188b" font="Regular;32" halign="center" name="buttonblue" position="1010,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget name="gemfury" position="1380,12" size="228,72" alphatest="on" />
		<widget name="info" position="1270,10" size="80,40" alphatest="on" />
		<widget name="menu" position="1270,50" size="80,40" alphatest="on" />
		<eLabel backgroundColor="grey" position="20,100" size="1600,2" />
		<widget name="config" position="30,120" size="1580,960" enableWrapAround="1" scrollbarMode="showOnDemand" />
		<eLabel backgroundColor="grey" position="20,1090" size="1600,2" />
		<widget name="text" foregroundColor="white" backgroundColor="background" position="20,1100" size="1620,50" font="Regular;42" zPosition="1" halign="center" valign="center" transparent="0" />
		</screen>"""
	else:
		skin = """
		<screen name="SvenH_Main" position="center,100" size="820,580">
		<widget name="logo" position="10,5" size="100,40" />
		<widget backgroundColor="#9f1313" font="Regular;16" halign="center" name="buttonred" position="115,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget backgroundColor="#1f771f" font="Regular;16" halign="center" name="buttongreen" position="245,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget backgroundColor="#a08500" font="Regular;16" halign="center" name="buttonyellow" position="375,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget backgroundColor="#18188b" font="Regular;16" halign="center" name="buttonblue" position="505,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget name="gemfury" position="690,6" size="114,36" alphatest="on" />
		<widget name="info" position="635,5" size="40,20" alphatest="on" />
		<widget name="menu" position="635,25" size="40,20" alphatest="on" />
		<eLabel backgroundColor="grey" position="10,50" size="800,1" />
		<widget name="config" position="15,60" size="790,480" enableWrapAround="1" scrollbarMode="showOnDemand" />
		<eLabel backgroundColor="grey" position="10,545" size="800,1" />
		<widget name="text" foregroundColor="white" backgroundColor="background" position="10,550" size="810,25" font="Regular;21" zPosition="1" halign="center" valign="center" transparent="0"/>
		</screen>"""

	def __init__(self, session, args = 0):
		Screen.__init__(self, session)
		
		url=getFeedUrl().split()[2]
		self.host,self.resolv = checkHost(url)
		cprint("FEED: %s HOST: %s" % (url,self.host))
		
		self.list = []
		# explizit check on every entry
		self.onChangedEntry = []
		self.onConfigEntryChanged = []
		ConfigListScreen.__init__(self, self.list, session = self.session, on_change = self.changedEntry)
		self.updates=[]
		self.onShown.append(self.setWindowTitle)
		self.updates=self.createSetup(True)
		self["buttonred"] = Label(_("Exit"))
		self["buttongreen"] = Label(_("Actions"))
		self["buttonyellow"] = Label(_("Update"))
		self["buttonblue"] = Label(_("About"))
		self["text"] = Label()
		self["logo"] = Pixmap()
		self["menu"] = Pixmap()
		self["info"] = Pixmap()
		self["gemfury"] = Pixmap()
		self.ipkg = IpkgComponent()
		self.ipkg.addCallback(self.ipkgCallback)
		cprint("restart not (yet) needed")
		self.restartNeeded=False
		HelpableScreen.__init__(self)   
		self["colorActions"] = HelpableActionMap(self, "ColorActions",
				{
				"red": (self.redPressed,_("Exit")),
				"green": (self.greenPressed,_("select actions")),
				"yellow": (self.okPressed,_("Package action")),
				"blue": (self.bluePressed,_("About")),
				}, -2)
		self["setupActions"] = HelpableActionMap(self, "SetupActions",
				{
				#"save": (self.save,_("Save")),
				"cancel": (self.redPressed,_("Exit")),
				"ok": (self.okPressed,_("Select")),
				"left": (self.ownKeyLeft,_("Left")),
				"right": (self.ownKeyRight,_("Right")),
				}, -2)
		self["channelSelectActions"] = HelpableActionMap(self, "ChannelSelectEPGActions",
				{
				"showEPGList": (self.infoPressed,_("Information about the package")),
				}, -2)
		text_menu=_("Setup open")
		self["menuActions"] = HelpableActionMap(self, "MenuActions",
				{
				"menu": (self.openSetup,text_menu),
				}, -2)
		# for new RC use Audio key as Help key alternative
		self["InfobarAudioSelectionActions"] = HelpableActionMap(self,"InfobarAudioSelectionActions",
				{
				"audioSelection": (self.audioPressed,_("show Help screen")),
				}, -3)
			
		#watch for filechanges
		self.filewatchStart()
		self.filewatchDebStart()

		if config.plugins.svenh.feed.value:
			addFeed(False) # if feed changed ...
			self.updateFeed(True) # quiet update on startup

	def audioPressed(self):
		audio2Help()

	def ownKeyLeft(self):
		self["config"].pageUp()

	def ownKeyRight(self):
		self["config"].pageDown()

	def filewatchStart(self):
		#Package-File
		self.md5_package = {}
		packagesList = getPackagesList()
		for packagefile in packagesList:
			if os_path.exists(packagefile):
				self.md5_package[packagefile] = hashlib.md5(open(packagefile,'rb').read()).hexdigest()
		self.filewatch_package = eFileWatch("/var/lib/apt/lists", False, eFileEvent.MOVE)
		self.filewatch_package_conn = self.filewatch_package.fileChanged.connect(self.filewatchEvent)
		self.filewatch_package.startWatching()

		self.md5_status = ""
		if os_path.exists(plugin_status_file):
			self.md5_status = hashlib.md5(open(plugin_status_file,'rb').read()).hexdigest()
		self.filewatch_status = eFileWatch("/var/lib/dpkg", False, eFileEvent.MOVE)
		self.filewatch_status_conn = self.filewatch_status.fileChanged.connect(self.filewatchEvent)
		self.filewatch_status.startWatching()

	def filewatchEvent(self, watch, event):
		dir = watch.getDirectory()
		filename = event.getFullPath()
		if filename == plugin_status_file:
			if os_path.exists(plugin_status_file):
				md5_status = hashlib.md5(open(plugin_status_file,'rb').read()).hexdigest()
				if md5_status != self.md5_status:
					cprint("CHANGED %s, %s call createSetup, %s, %s" % (dir, filename, self.md5_status, md5_status))
					self.md5_status = md5_status
					self.updates=self.createSetup()
					self.updateWindowTitle()
		packagesList=getPackagesList()
		#print(">>>> filename, packages", filename, packagesList)
		if filename in packagesList:
			if os_path.exists(filename):
				md5_package = hashlib.md5(open(filename,'rb').read()).hexdigest()
				if md5_package != self.md5_package.get(filename,0):
					cprint("CHANGED %s, %s call createSetup, %s, %s" % (dir, filename, self.md5_package.get(filename,0), md5_package))
					self.md5_package[filename] = md5_package
					self.updates=self.createSetup()
					self.updateWindowTitle()

	def filewatchDebStart(self):
		#local feed
		if config.plugins.svenh.local.value != "none":
			deb_directory = self.getLocalPath()
			self.filewatch_deb = eFileWatch(deb_directory, False, eFileEvent.CLOSE_WRITE | eFileEvent.DELETE)
			self.filewatch_deb_conn = self.filewatch_deb.fileChanged.connect(self.filewatchEventDeb)
			self.filewatch_deb.startWatching()
		else:
			self.filewatch_deb = None

	def filewatchDebStop(self):
		if self.filewatch_deb and self.filewatch_deb.isWatching():
			self.filewatch_deb.stopWatching()

	def filewatchEventDeb(self, watch, event):
		filename = event.getFullPath()
		directory = self.getLocalPath()
		boxkit=getArch()+".deb"
		if filename.endswith("all.deb") or filename.endswith(boxkit):
			cprint("CHANGED LOCAL FEED %s, %s call createSetup" % (dir, filename))
			self.updates=self.createSetup()
			self.updateWindowTitle()

	def getLocalPath(self):
		if config.plugins.svenh.local.value == "user":
			deb_directory = "%s" % config.plugins.svenh.local_user_path.value
		else:
			deb_directory = "/%s" % config.plugins.svenh.local.value
		return deb_directory

	def infoPressed(self):
		self.open_info()

	def bluePressed(self):
		self.session.open(MessageBox, _("Feed Plugin v%s by Sven H (2022)") % plugin_version, MessageBox.TYPE_INFO, timeout=plugin_timeout)

	def showLastLog(self):
		if os_path.exists(plugin_log):
			cmd = "cat %s" % plugin_log
			self.session.open(Console,plugin_log,[cmd])
		else:
			self.session.open(MessageBox, _("none")+ " "+plugin_log, MessageBox.TYPE_ERROR)

	def changeFeedCallback(self, answer):
		cprint(">>>>>>> changeFeedCallback, %s %s" % (answer,self.new_feed))
		if answer:
			removeFeed()
			config.plugins.svenh.feed_version.value = self.new_feed
			config.plugins.svenh.feed_version.save()
			cprint("new feed_version: %s" % config.plugins.svenh.feed_version.value)
			self.md5_package = {}
			addFeed(update=False)
			self.aptUpdate()
			self.session.open(MessageBox, _("Trying to download a new packetlist. Please wait..."), MessageBox.TYPE_INFO, timeout=plugin_timeout)

	def greenPressed(self):
		cur = self["config"].getCurrentIndex()
		list = []
		list.append((_("Package list update"), "feed_update"))
		list.append((_("Package list update complete (upgrade)"), "feed_upgrade"))
		list.append((_("Package list update reset (repair)"), "feed_repair"))
		if len(self.updates) > 0:
			list.append((_("Update all available updates"), "update_available"))
		if cur and config.plugins.svenh.local.value != "none":
			if len(self.argument[cur])>2 and not self.argument[cur][6]:
			#print(cur, self["config"].getCurrent()[0], self.argument[cur][6])
				list.append((_("Download") + ": '" + self["config"].getCurrent()[0] + "' -> " + self.getLocalPath(), "download_deb"))
		if cur and len(self.argument[cur])>2 and self.argument[cur][6]:
			#print(cur, self["config"].getCurrent()[0], self.argument[cur][6])
			list.append((_("Delete") + ": '" + self["config"].getCurrent()[0] + "' -> " + self.getLocalPath(), "delete_deb"))
		list.append((_("Show Log")+": "+plugin_log, "showLastLog"))
		self.session.openWithCallback(
				self.menuCallback,
				ChoiceBox,
				title = _("Following tasks will be done after you press OK!").replace("!",":"),
				windowTitle = getTitle(),
				list = list,
		)

	def openSetup(self):
		self.session.openWithCallback(self.setupCallback,SvenH_Setup)
	
	def menuCallback(self, ret):
		ret = ret and ret[1]
		if ret:
			if ret == "feed_update":
				self.session.open(MessageBox, _("Trying to download a new packetlist. Please wait..."), MessageBox.TYPE_INFO, timeout=plugin_timeout)
				self.aptUpdate()
			elif ret == "feed_upgrade":
				text = "all upcoming updates will be installed (also from all other feeds)."
				text+= "\n\nDo you really want to update all upcoming updates ?"
				self.session.openWithCallback(self.feedUpgradeCallback, MessageBox, text)
			elif ret == "feed_repair":
				self.feedRepair()
			elif ret == "update_available":
				feed_updates = []
				local_updates = []
				cmd = ""
				for package in self.argument:
					if len(package) > 3 and package[3] == UPDATENEEDED and package[6]:
						local_updates.append(package[6])
					elif len(package) > 3 and package[3] == UPDATENEEDED:
						feed_updates.append(package[2])
				all_feed_updates = " ".join(feed_updates)
				all_local_updates = " ".join(local_updates)
				self.deb = all_feed_updates + all_local_updates
				cprint("update all: %s" % all_feed_updates)
				title = _("available updates")
				if all_feed_updates:
					cmd = "apt-get -o=Dpkg::Use-Pty=0 --reinstall --only-upgrade install %s -f -y --assume-yes; apt-get -o=Dpkg::Use-Pty=0 install -f -y --assume-yes"  % (all_feed_updates)
				if all_local_updates:
					if cmd:
						cmd += "; "
					cmd += "dpkg --force-all -i %s; apt-get -o=Dpkg::Use-Pty=0 install -f -y --assume-yes" % (all_local_updates)
				self.session.openWithCallback(self.finishedConsole,Console,_(title),[cmd], None, False, plugin_log)
			elif ret == "download_deb":
				cur = self["config"].getCurrentIndex()
				if cur and len(self.argument[cur])>2 and not self.argument[cur][6]:
					text=_("Do you really want to continue?")
					replacestr=" "+_("Downloading").lower()+" %s?" % self.argument[cur][2]
					print(self.argument[cur])
					question=text.replace("?",replacestr)
					self.session.openWithCallback(self.downloadDebCallback, MessageBox, question, MessageBox.TYPE_YESNO)
			elif ret == "delete_deb":
				cur = self["config"].getCurrentIndex()
				if cur and len(self.argument[cur])>2 and self.argument[cur][6] and os_path.exists(self.argument[cur][6]):
					self.session.openWithCallback(self.deleteDebCallback, MessageBox, _("Do you really want to delete %s?") % self.argument[cur][6], MessageBox.TYPE_YESNO)
			elif ret == "showLastLog":
				self.showLastLog()

	def feedUpgradeCallback(self, ret):
		cprint(">>>> feedUpgradeCallback %s" % ret)
		if ret:
			self.session.open(MessageBox, _("Trying to download a new packetlist. Please wait...").replace("...","")+" for "+_("Software update"), MessageBox.TYPE_INFO, timeout=plugin_timeout)
			self.aptUpgrade()

	def setupCallback(self, ret):
		cprint(">>>> setupCallback %s" % ret)
		if ret:
			self["buttonyellow"].setText(" ")
			if config.plugins.svenh.feed.value:
				addFeed(update=False)
				self.aptUpdate()
			else:
				removeFeed()
				self.md5_package = {}
			self.updates = self.createSetup()
			self.updateWindowTitle()
			
			if config.plugins.svenh.local.value != "none":
				self.filewatchDebStart()
			else:
				self.filewatchDebStop()

	def downloadDebCallback(self, ret):
		if ret:
			cur = self["config"].getCurrentIndex()
			if len(self.argument[cur])>2 and not self.argument[cur][6]:
				self.download_directory = self.getLocalPath()
				self.download_kit=self.argument[cur][2]
				cmd = "cd %s; rm %s*.deb; apt-get -o=Dpkg::Use-Pty=0 download %s"  % (self.download_directory,self.download_kit,self.download_kit)
				self.download = eConsoleAppContainer()
				self.download_conn = self.download.appClosed.connect(self.downloadDebFinished)
				self.download.execute(cmd)

	def downloadDebFinished(self, ret):
		text=_("Download")+" "+self.download_directory+"/"+self.download_kit+" "+_("Execution finished!!").replace("!!","!")
		self.session.open(MessageBox, text, MessageBox.TYPE_INFO, timeout=plugin_timeout)

	def deleteDebCallback(self, ret):
		if ret:
			cur = self["config"].getCurrentIndex()
			if len(self.argument[cur])>2 and self.argument[cur][6] and os_path.exists(self.argument[cur][6]):
				os_remove(self.argument[cur][6])
				cprint("delete local deb: %s" % self.argument[cur][6])
				#reload createSetup with Filewatcher after delete

	def feedRepair(self):
		cprint("menu pressed")
		if checkApt():
			checkApt(True)
			# repair stranded locks
			if os_path.exists("/var/lib/apt/lists/lock"):
				os_remove("/var/lib/apt/lists/lock")
			if os_path.exists("/var/lib/apt/lists/lock"):
				os_remove("/var/lib/apt/lists/lock")
			if checkApt(): # should NOT be true anymore ...
				self.session.open(MessageBox, _("Upgrading Dreambox... Please wait"), MessageBox.TYPE_ERROR, timeout=plugin_timeout)
			else:
				self.session.open(MessageBox, _("There was an error downloading the packetlist. Please try again."), MessageBox.TYPE_WARNING, timeout=plugin_timeout)
		else:
			# repair the rest
			cmd = "dpkg --configure -a; apt-get -qq -o=Dpkg::Use-Pty=0 update; apt-get -qq -o=Dpkg::Use-Pty=0 install -f -y --assume-yes; apt-get autoremove -f -y --assume-yes; apt-get -qq -o=Dpkg::Use-Pty=0 clean"
			title=_("Feed repair")
			start_text = _("Feed repair is running. Please wait ...")
			self.session.open(Console,_(title),[cmd], None, False, plugin_log, start_text)

	def selectionChanged(self):
		cprint(">>>> selectionChanged")
		cur = self["config"].getCurrentIndex()
		if self["config"].getCurrent()[1] == config.plugins.svenh.package_empty:
			self["buttonblue"].setText(" ") #- dont set because on start ipkgupdate set to "...."
			self["buttonyellow"].setText(" ")
		else:
			task=self.argument[cur][3]
			if task==INSTALLABLE:
				self["buttonyellow"].setText(_("Install"))
			elif task==UPDATENEEDED:
				self["buttonyellow"].setText(_("Update"))
			elif task==DOWNGRADE:
				self["buttonyellow"].setText(_("Downgrade"))
			else:   # UNINSTALL
				self["buttonyellow"].setText(_("Uninstall"))
			
			if self["buttonblue"].getText() == " ":
				self["buttonblue"].setText(_("About")) #- dont set because on start ipkgupdate set to "...."
			
			if not self["text"].getText().startswith(_("State")):
				name = self.argument[cur][0] # plugin name
				if config.plugins.svenh.show_info.value == "desc":
					description = " ".join(self.argument[cur][1]).replace("  ", " ") # merge description lines
					if description != name:
						description = description.replace(name,"") # description without name
					self["text"].setText(_("Description") + ": " + description) # show description in the info-line
				else:
					self["text"].setText(_("Name") + ": " + self.argument[cur][2]) # show packagename

	def createSetup(self, first=False):
		global statusfile_data
		statusfile_data = ""
		updates=[]
		self.list = []
		self.argument = []
		self.list_update_all = []
		self.argument_update_all = []
		
		r = 0
		if self.resolv is None:
			error=_("Your dreambox isn't connected to the internet properly. Please check it and try again.")
			err=error.split(".")
			self.list.append(getConfigListEntry(err[0], config.plugins.svenh.package_empty))
			if len(err) > 1:
				self.list.append(getConfigListEntry(err[1], config.plugins.svenh.package_empty))
			self["config"].list = self.list
			self["config"].l.setList(self.list)
			return []
		if config.plugins.svenh.feed.value:
			feedList = []
			feedList.append(plugin_feedName)
			for feedname in feedList:
				packages_file = getPackages(feedname)
				content=""
				if os_path.exists(packages_file):
					f=open(packages_file,"r")
					content = f.read()
					f.close()
				#cprint(">>>> package: %s" % packages_file)
				#cprint(">>>> createSetup len content: %d" % len(content))
				if len(content) > 0 and config.plugins.svenh.listview.value!="false":
					
					self.argument.append((str(r)))
					r+=1
					self.list.append(("%s %s (c) %s %s" % (gheader,_("Plugins"),feedname,gtrailer), ))
					content=content.replace("\n ",", ").replace("\n ",", ")
					upackages=content.strip().split("\n\n")
					packages=sortPackages(upackages)
					x=0
					boxarch=getArch()

					#sorting by status (updates first) or by AZ
					self.list_update = []
					self.list_new    = []
					self.list_none   = []
					self.argument_update = []
					self.argument_new    = []
					self.argument_none   = []
					svenh_argument=None
					for package in packages:
						desc=package['Description'].split(",")
						name=package['PackageName']
						parch=package['Architecture']
						if (parch=="all" or parch==boxarch):
							kit=name
							new=package['Version'].strip()
							current=currentVersion(package['Package'])
							#fix for CSP-Version from DP-Feed - for example 0.1.0-r8+git0+570434d592-r0.0
							gitPos = current.find("+git")
							#print(">>> name", name)
							if name == "ChannelSelection Plus" and gitPos>0:
								current = current[:gitPos]
							#print(">>> currentversion", current)
							deb=package['Package']
							depends=None
							try:
								depends=package['Depends'].split(",")
							except:
								pass
							if not depends is None:
								for dep in depends:
									if dep.find(feedPlugin_PackageName) != -1:
										depends.remove(dep)
								if len(depends) < 1:
									depends=None
							if config.plugins.svenh.version.value:
								kit+=" v%s" % new
							if config.plugins.svenh.size.value:
								size=int(package['Size'])//1024
								kit+=" - %dkB" % (size)
							debkit=None
							if "SvenH Feed-Plugin" in name:
								try:
									date=package['Date'].strip()
									sp=date.split()
									ymd="%s%s%02d" % (sp[3],abbr_to_num(sp[2]),int(sp[1]))
									new=new+"-"+ymd
								except:
									pass
							#cprint("current: %s new: %s" % (current,new))
							if current == _("none"):
								status=INSTALLABLE
							elif Version(current) == Version(new):
								status=INSTALLED
							elif Version(current) > Version(new):
								status=DOWNGRADE
							else:
								status=UPDATENEEDED
							if "SvenH Feed-Plugin" in name:
								svenh_argument = (name,desc,deb,status,new,depends,debkit,feedname)
							if config.plugins.svenh.listview.value != "sort":
								if current == _("none"):
									self.list.append(getConfigListEntry(kit, config.plugins.svenh.package_install))
								elif Version(current) == Version(new):
									self.list.append(getConfigListEntry(kit, config.plugins.svenh.package_uninstall))
								elif Version(current) > Version(new):
									self.list.append(getConfigListEntry(kit, config.plugins.svenh.package_downgrade))
								else:
									self.list.append(getConfigListEntry(kit, config.plugins.svenh.package_update))
									updates.append(deb)
									
									self.list_update.append(getConfigListEntry(kit, config.plugins.svenh.package_update))
									self.argument_update.append((name,desc,deb,status,new,depends,debkit,feedname))
								# arguments for real plugins
								self.argument.append((name,desc,deb,status,new,depends,debkit,feedname))
							else:
								if current == _("none"):
									self.list_none.append(getConfigListEntry(kit, config.plugins.svenh.package_install))
									self.argument_none.append((name,desc,deb,status,new,depends,debkit,feedname))
								elif Version(current) == Version(new):
									self.list_new.append(getConfigListEntry(kit, config.plugins.svenh.package_uninstall))
									self.argument_new.append((name,desc,deb,status,new,depends,debkit,feedname))
								elif Version(current) > Version(new):
									self.list_new.append(getConfigListEntry(kit, config.plugins.svenh.package_downgrade))
									self.argument_new.append((name,desc,deb,status,new,depends,debkit,feedname))
								else:
									self.list_update.append(getConfigListEntry(kit, config.plugins.svenh.package_update))
									self.argument_update.append((name,desc,deb,status,new,depends,debkit,feedname))
									updates.append(deb)

					if config.plugins.svenh.listview.value == "sort":
						self.list.extend(self.list_update)
						self.argument.extend(self.argument_update)
						self.list.extend(self.list_new)
						self.argument.extend(self.argument_new)
						self.list.extend(self.list_none)
						self.argument.extend(self.argument_none)

					if not svenh_argument is None:
						#set feed plugin to first
						idx = self.argument.index(svenh_argument)
						entry = self.argument.pop(idx)
						self.argument.insert(1,entry)
						entry = self.list.pop(idx)
						self.list.insert(1,entry)
					
					if self.list_update: # fill update_all over all feeds
						self.list_update_all.extend(self.list_update)
						self.argument_update_all.extend(self.argument_update)

		if config.plugins.svenh.local.value != "none":
			directory = self.getLocalPath()
			self.list.append(("%s %s %s %s" % (gheader,_("Plugins"), directory,gtrailer), ))
			r+=1
			self.argument.append((str(r)))
			boxkit=getArch()+".deb"
			self.list_update = []
			self.list_new    = []
			self.list_none   = []
			self.list_down   = []
			self.argument_update = []
			self.argument_new    = []
			self.argument_none   = []
			self.argument_down   = []
			feedname="local"
			filelist = sorted(os_listdir(directory))
			for file in filelist:
				if file.endswith("all.deb") or file.endswith(boxkit):
					# should be moved were needed ... too slow ...
					#changelog,copyright,readme=parseDoc(directory,file)
					#cprint("changelog: %s copyright: %s README: %s" % (changelog,copyright,readme))
					name,desc,deb,status,new,depends,md5sums=parseDeb(directory,file)
					kit=name
					current=currentVersion(deb, feedDeb=False)
					#fix for CSP-Version from DP-Feed - for example 0.1.0-r8+git0+570434d592-r0.0
					gitPos = current.find("+git")
					if name == "ChannelSelection Plus" and gitPos>0:
						current = current[:gitPos]
					#print(">>> currentversion", current)
					if current == _("none"):
						status=INSTALLABLE
					elif Version(current) == Version(new):
						status=INSTALLED
					elif Version(current) > Version(new):
						status=DOWNGRADE
					else:
						status=UPDATENEEDED
					if not depends is None:
						for dep in depends:
							if dep.find(feedPlugin_PackageName) != -1:
								depends.remove(dep)
						if len(depends) < 1:
							depends=None
					if config.plugins.svenh.version.value:
						kit+=" v%s" % new
					if config.plugins.svenh.size.value:
						stat=os_stat("%s/%s" % (directory,file))
						kit+=" - %dkB" % (int(stat.st_size//1024))
					debkit="%s/%s" % (directory,file)
					if config.plugins.svenh.listview.value!="sort":
						if current == _("none"):
							self.list.append(getConfigListEntry(kit, config.plugins.svenh.package_install))
						elif Version(current) == Version(new):
							self.list.append(getConfigListEntry(kit, config.plugins.svenh.package_uninstall))
						elif Version(current) > Version(new):
							self.list.append(getConfigListEntry(kit, config.plugins.svenh.package_downgrade))
						else:
							self.list.append(getConfigListEntry(kit, config.plugins.svenh.package_update))
							updates.append(deb)
							self.list_update.append(getConfigListEntry(kit, config.plugins.svenh.package_update))
							self.argument_update.append((name,desc,deb,status,new,depends,debkit,feedname))
							updates.append(deb)
						# arguments for real plugins
						#cprint("name %s desc %s deb %s status %s new %s depends %s" %  (name,desc,deb,status,new,depends))
						self.argument.append((name,desc,deb,status,new,depends,debkit,feedname))
					else:
						if current == _("none"):
							self.list_none.append(getConfigListEntry(kit, config.plugins.svenh.package_install))
							self.argument_none.append((name,desc,deb,status,new,depends,debkit,feedname))
						elif Version(current) == Version(new):
							self.list_new.append(getConfigListEntry(kit, config.plugins.svenh.package_uninstall))
							self.argument_new.append((name,desc,deb,status,new,depends,debkit,feedname))
						elif Version(current) > Version(new):
							self.list_down.append(getConfigListEntry(kit, config.plugins.svenh.package_downgrade))
							self.argument_down.append((name,desc,deb,status,new,depends,debkit,feedname))
						else:
							self.list_update.append(getConfigListEntry(kit, config.plugins.svenh.package_update))
							self.argument_update.append((name,desc,deb,status,new,depends,debkit,feedname))
							updates.append(deb)
			
			if config.plugins.svenh.listview.value == "sort":
				self.list.extend(self.list_update)
				self.argument.extend(self.argument_update)
				self.list.extend(self.list_new)
				self.argument.extend(self.argument_new)
				self.list.extend(self.list_none)
				self.argument.extend(self.argument_none)
				self.list.extend(self.list_down)
				self.argument.extend(self.argument_down)
			
			if self.list_update: # fill update_all over all feeds and local
				self.list_update_all.extend(self.list_update)
				self.argument_update_all.extend(self.argument_update)
		
		#updates = list( dict.fromkeys(updates) ) # delete duplicates from local
		
		# show all updates on top of the list
		if config.plugins.svenh.show_update_section.value and self.list_update_all: 
			self.list_update_all.extend(self.list)
			self.argument_update_all.extend(self.argument)
			self.list = self.list_update_all
			self.argument = self.argument_update_all
			self.list.insert(0,("%s %s %s %s" % (gheader,_("Plugins"), _("Updates"),gtrailer), ))
			self.argument.insert(0,("0"))
		
		if len(self.list) == 1: #avoid gs if list has only a section, but not packages
			self.list.append(getConfigListEntry(" no package found", config.plugins.svenh.package_empty))
			self.argument.append(("no package","no desc"))
		
		if len(self.list) == 0: #if feed is disabled
			self.list.append(getConfigListEntry(" not activated - go to setup on menu-key", config.plugins.svenh.package_empty))
			self.argument.append(("not activated","not activated"))
			
		self["config"].list = self.list
		self["config"].l.setList(self.list)
		if first:
			self["config"].onSelectionChanged.append(self.selectionChanged)
		print(updates)
		return updates

	def keyNumberGlobal(self, number):
		pass #to prevent changedEntry on any KeyNumber pressed

	def changedEntry(self):
		cprint(">>>> changedEntry")

	def setWindowTitle(self):
		self.updateWindowTitle()
		self["logo"].instance.setPixmapFromFile("%s/plugin.png" % plugindir)
		self["gemfury"].instance.setPixmapFromFile("%s/gemfury.png" % plugindir)
		self["menu"].instance.setPixmapFromFile(getPiconPath("menu"))
		self["info"].instance.setPixmapFromFile(getPiconPath("info"))

	def updateWindowTitle(self):
		if len(self.updates) > 0:
			self.setTitle(getTitle()+" v"+plugin_version+" (%d %s)" % (len(self.updates),_("Update")))
		else:
			self.setTitle(getTitle()+" v"+plugin_version)

	def redPressed(self):
		if self.restartNeeded:
			cprint("restart handling")
			self.restartHandling(False)
		else:
			cprint("direct close")
			self.close(False)

	def cancel(self,answer):
		if answer:
			for x in self["config"].list:
				if len(x) > 1:
					x[1].cancel()
			if config.plugins.svenh.feed.value:
				addFeed()
			else:
				removeFeed()
			if self.restartNeeded:
				cprint("restart handling")
				self.restartHandling(False)
			else:
				cprint("direct close")
				self.close(False)
		else:
			if not os_path.exists(plugin_feedlist) and config.plugins.svenh.feed.value:
				addFeed()

	def open_info(self):
		cur = self["config"].getCurrentIndex()
		if not cur or self["config"].getCurrent()[1] == config.plugins.svenh.package_empty:
			return
		
		if config.plugins.svenh.version.value:
			title=_("About")+" "+self.argument[cur][0]+" V"+self.argument[cur][4]
		else:
			title=_("About")+" "+self.argument[cur][0]
		header=self.argument[cur][0] # name
		# merge description lines
		footer=" ".join(self.argument[cur][1])
		footer=footer.replace(header,"") # description without name
		package=self.argument[cur][2]
		package_status=self.argument[cur][3]
		localdeb = self.argument[cur][6]
		feedname = self.argument[cur][7]
		cprint("INFO: %s %s %s %s %s %s" % (title,header,footer, package, package_status,localdeb))
		title = _("Info") + " " + header
		self.session.open(SvenH_Info, title, header, footer, package, package_status, localdeb, feedname)

	def aptUpgrade(self):
		# apt get update should be already done ...
		cprint("apt-get upgrade")
		upgrade_args = {'use_maintainer' : False, 'test_only': False}
		self.ipkg.startCmd(IpkgComponent.CMD_UPGRADE,upgrade_args)
		self["text"].setText(_("State") + ": " + _("Update")+" "+_("In Progress")+" ......")

	def aptUpdate(self):
		cprint("apt-get update")
		self["text"].setText(_("State") + ": " + _("Update")+" "+_("In Progress")+" ...")
		self.ipkg.startCmd(IpkgComponent.CMD_UPDATE)

	def ipkgCallback(self, event, param = None):
		if event == self.ipkg.EVENT_DONE:
			cprint("apt-get done")
			self["text"].setText("")
			self.selectionChanged() #change info-text after aptUpdate
			#self.createSetup() # call from filewatcher

	def updateFeed(self,quiet=False):
		if config.plugins.svenh.feed.value:
			if not quiet:
				self.session.open(MessageBox, _("Trying to download a new packetlist. Please wait..."), MessageBox.TYPE_INFO, timeout=plugin_timeout)
			cprint("updateFeed aptUpdate")
			self.aptUpdate()

	def okPressed(self):
		cur = self["config"].getCurrentIndex()
		current = self["config"].getCurrent()
		if cur == 0 or self["config"].getCurrent()[1] == config.plugins.svenh.package_empty:
			return
		
		if len(self.argument[cur])<3:
			return
		if checkApt():
			self.session.open(MessageBox, _("Upgrading Dreambox... Please wait"), MessageBox.TYPE_ERROR, timeout=plugin_timeout)
		else:
			self.name=self.argument[cur][0]
			self.desc=self.argument[cur][1]
			self.deb=self.argument[cur][2]
			self.task=self.argument[cur][3]
			self.new=self.argument[cur][4]
			self.depends=self.argument[cur][5]
			self.debkit=self.argument[cur][6]
			if self.task==INSTALLABLE:
				text=_("This plugin will be installed")+": %s ?" % self.name
				if config.plugins.svenh.confirm.value=="true":
					self.session.openWithCallback(self.debInstall,MessageBox,text,MessageBox.TYPE_YESNO)
				else:
					self.debInstall(True)
			elif self.task==UPDATENEEDED:
				text=_("Do you want to upgrade the package: %s") % self.name
				if config.plugins.svenh.confirm.value=="true":
					self.session.openWithCallback(self.debInstall,MessageBox,text,MessageBox.TYPE_YESNO)
				else:
					self.debInstall(True)
			elif self.task==DOWNGRADE:
				if "SvenH Feed-Plugin" in self.name:
					if config.plugins.svenh.confirm.value!="false":
						text=_("Downgrade")+" %s " % self.name +_("disabled")
						self.session.open(MessageBox,text, MessageBox.TYPE_ERROR)
				else:
					tt=_("There might not be enough Space on the selected Partition.\nDo you really want to continue?")
					sp=tt.split("\n")
					if len(sp) > 1:
						text=_("Downgrade")+" %s. " % self.name+sp[1]
					else:
						text=_("Downgrade")+" %s?)" % self.name
					if config.plugins.svenh.confirm.value=="true":
						self.session.openWithCallback(self.debInstall,MessageBox,text, MessageBox.TYPE_YESNO)
					else:
						self.debInstall(True)
			else:
				if "SvenH Feed-Plugin" in self.name:
					if config.plugins.svenh.confirm.value!="false":
						text=_("This plugin will be removed")+":\n - %s" % self.name
						text+="\n\n\n" + _("All other installed plugins from the feed will not be removed.")
						text+="\n\n" + _("Do you really want to remove this feed plugin?")
						self.session.openWithCallback(self.debInstall,MessageBox,text,MessageBox.TYPE_YESNO)
				else:
					text=_("This plugin will be removed")+": %s" % self.name
					if config.plugins.svenh.confirm.value=="true":
						self.session.openWithCallback(self.debInstall,MessageBox,text,MessageBox.TYPE_YESNO)
					else:
						self.debInstall(True)

	def skipInstall(self):
		text=_("No, do nothing.").replace(".","!")
		self.session.open(MessageBox,text, MessageBox.TYPE_WARNING)

	def debInstall(self,answer):
		if answer is None:
			self.skipInstall()
		elif answer is False:
			self.skipInstall()
		else:
			if not self.debkit is None:
				cprint("package: %s kit: %s version: %s" % (self.deb,self.debkit,self.new))
				script=""
				if self.task==INSTALLABLE:
					title = _("This plugin will be installed")+": %s" % self.name
					cmd = "dpkg --force-all -i %s; apt-get -o=Dpkg::Use-Pty=0 install -f -y --assume-yes%s"  % (self.debkit,script)
				elif self.task==UPDATENEEDED:
					title = _("This plugin will be updated")+": %s" % self.name
					cmd = "apt-mark unhold %s > /dev/null 2>&1; dpkg --force-all -i %s; apt-get -o=Dpkg::Use-Pty=0 install -f -y --assume-yes%s"  % (self.deb, self.debkit,script)
				elif self.task==DOWNGRADE:
					title = _("This plugin will be downgrade")+": %s" % self.name
					cmd = "apt-mark unhold %s > /dev/null 2>&1; dpkg --force-all -i %s; apt-get -o=Dpkg::Use-Pty=0 install -f -y --assume-yes%s"  % (self.deb, self.debkit, script)
				else:   # UNINSTALL
					title = _("This plugin will be removed")+": %s" % self.name
					cmd = "apt-mark unhold %s > /dev/null 2>&1; dpkg --force-all -r %s; apt-get -o=Dpkg::Use-Pty=0 autoremove -f -y --assume-yes"  % (self.deb, self.deb)
			else:
				cprint("package: %s version: %s" % (self.deb,self.new))
				script=""
				if self.task==INSTALLABLE:
					title = _("This plugin will be installed")+": %s" % self.name
					cmd = "apt-get -o=Dpkg::Use-Pty=0 install %s -f -y --assume-yes; apt-get install -o=Dpkg::Use-Pty=0 -f -y --assume-yes%s"  % (self.deb,script)
				elif self.task==UPDATENEEDED:
					title = _("This plugin will be updated")+": %s" % self.name
					cmd = "apt-get -o=Dpkg::Use-Pty=0 --reinstall --only-upgrade install %s -f -y --assume-yes; apt-get -o=Dpkg::Use-Pty=0 install -f -y --assume-yes%s"  % (self.deb,script)
				elif self.task==DOWNGRADE:
					title = _("This plugin will be downgrade")+": %s" % self.name
					cmd = "apt-get -o=Dpkg::Use-Pty=0 --only-upgrade install %s=%s -f -y --allow-downgrades; apt-get -o=Dpkg::Use-Pty=0 install -f -y --assume-yes%s"  % (self.deb, self.new, script)
				else:   # UNINSTALL
					title = _("This plugin will be removed")+": %s" % self.name
					cmd = "apt-get -o=Dpkg::Use-Pty=0 remove %s -f -y --assume-yes; apt-get -o=Dpkg::Use-Pty=0 autoremove -f -y --assume-yes"  % (self.deb)

			self.session.openWithCallback(self.finishedConsole,Console,_(title),[cmd], None, False, plugin_log)

	def finishedConsole(self):
		if self.deb != feedPlugin_PackageName:
			self.restartNeeded=True
		elif self.deb == feedPlugin_PackageName and self.task==INSTALLED: #after uninstalling feed-plugin
			removeFeed()
			self.md5_package = {}
			self.restartNeeded=True
		self.updates=self.createSetup()
		self.updateWindowTitle()
		cprint("restart needed ... later")
		#print(">>> installed deb: '%s', task: '%s'" % (self.deb, self.task))

	def restartHandling(self,option=True):
		self.option=option
		if config.plugins.svenh.confirm.value=="info":
			text=_("Restart required") + "\n\n" + _("Restart GUI")+"!"
			self.session.openWithCallback(self.doExit,MessageBox,text, MessageBox.TYPE_INFO)
		elif config.plugins.svenh.confirm.value=="true":
			text=_("Restart required") + "\n\n" + _("Restart GUI")+"?"
			self.session.openWithCallback(self.doRestart, MessageBox,text, MessageBox.TYPE_YESNO)
		else:   # false has currently no action - except closing ...
			self.close(self.option)

	def doRestart(self,answer):
		if answer is None:
			return
		if answer is False:
			self.close(self.option)
		else:
			self.session.open(TryQuitMainloop, 3)
			self.close()

	def doExit(self,answer):
		if answer is None:
			return
		if answer is False:
			return
		else:
			self.close(self.option)

#fix SSL error with getPage
from twisted.internet.ssl import ClientContextFactory
from twisted.internet._sslverify import ClientTLSOptions
try:
	from urllib.parse import urlparse
except ImportError:
	from urlparse import urlparse

class downloaderClientContextFactory(ClientContextFactory):
	def __init__(self, url=None):
		domain = urlparse(url).netloc
		self.hostname = domain
	
	def getContext(self, hostname=None, port=None):
		ctx = ClientContextFactory.getContext(self)
		if self.hostname and ClientTLSOptions is not None:
			ClientTLSOptions(self.hostname, ctx)
		return ctx

class fileDownloader:
	def __init__(self, file):
		cprint("fileDownloader::init file=%s" % (file))
		self.urlbase=file

	def getList(self, callback, errback):
		cprint("fileDownloader:getList %s" % self.urlbase)
		self.callback = callback
		self.errback = errback
		header = {"Cache-Control": "no-cache", "Pragma": "no-cache"}
		onwContextFactory = downloaderClientContextFactory(self.urlbase) if "https" in self.urlbase else None
		getPage(self.urlbase, contextFactory = onwContextFactory, headers=header).addCallback(self.file_finished).addErrback(self.file_failed)

	def file_failed(self, failure_instance):
		cprint("fileDownloads:file_failed %s" % self.urlbase)
		self.errback(failure_instance.getErrorMessage())

	def file_finished(self, file):
		cprint("fileDownloader:file_finished %s" % self.urlbase)
		self.callback(file)

class CheckPackages(Screen):
	def __init__(self, session):
		Screen.__init__(self, session)
		cprint("STARTS watching Packages File")
		# always watch for Package file changes...
		self.md5_package = {}
		packagesList = getPackagesList()
		for packagefile in packagesList:
			if os_path.exists(packagefile):
				self.md5_package[packagefile] = hashlib.md5(open(packagefile,'rb').read()).hexdigest()
		self.filewatcher = eFileWatch("/var/lib/apt/lists", False, eFileEvent.MOVE)
		self.filewatcher_conn = self.filewatcher.fileChanged.connect(self.fileEvent)
		self.filewatcher.startWatching()

	def fileEvent(self, watch, event):
		dir = watch.getDirectory()
		filename = event.getFullPath()
		packagesList=getPackagesList()
		print(">>>> filename, packages", filename, packagesList)
		if filename in packagesList:
			if os_path.exists(filename):
				md5_package = hashlib.md5(open(filename,'rb').read()).hexdigest()
				if md5_package != self.md5_package.get(filename,0):
					cprint("CHANGED %s, %s call metaDreamy, %s, %s" % (dir, filename,self.md5_package.get(filename,0), md5_package))
					self.md5_package[filename] = md5_package
					# check Packages file for changes ...
					metaDreamy(config.plugins.svenh.feed.value)

class SvenH_Info(Screen,HelpableScreen):
	if sz_w == 1920:
		skin = """
		<screen name="SvenH_Info" position="center,170" size="1200,890" >
		<widget name="logo" position="20,10" size="150,60" />
		<widget backgroundColor="#9f1313" font="Regular;26" halign="center" name="buttonred" position="180,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget backgroundColor="#1f771f" font="Regular;26" halign="center" name="buttongreen" position="370,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget backgroundColor="#a08500" font="Regular;26" halign="center" name="buttonyellow" position="560,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget backgroundColor="#18188b" font="Regular;26" halign="center" name="buttonblue" position="750,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget name="infokey" position="935,10" size="60,30" alphatest="on" />
		<widget name="menukey" position="935,40" size="60,30" alphatest="on" />
		<widget name="gemfury" position="1002,12" size="177,56" alphatest="on" />
		<eLabel backgroundColor="grey" position="20,90" size="1160,1" />
		<eLabel backgroundColor="grey" position="20,740" size="1160,1" />
		<widget name="about" foregroundColor="yellow" position="20,750" size="1160,50" halign="center" valign="center" font="Regular;36"/>
		<eLabel backgroundColor="grey" position="20,810" size="1160,1" />
		<widget name="info" position="20,820" size="1160,50" halign="center" valign="center" foregroundColor="yellow" font="Regular;28"/>
		<widget name="text" position="20,120" size="1160,600" font="Regular;26"/>
		</screen>"""
	elif sz_w == 2560:
		skin = """
		<screen name="SvenH_Info" position="center,200" size="1640,1160" >
		<widget name="logo" position="20,10" size="200,80" />
		<widget backgroundColor="#9f1313" font="Regular;32" halign="center" name="buttonred" position="230,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget backgroundColor="#1f771f" font="Regular;32" halign="center" name="buttongreen" position="490,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget backgroundColor="#a08500" font="Regular;32" halign="center" name="buttonyellow" position="750,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget backgroundColor="#18188b" font="Regular;32" halign="center" name="buttonblue" position="1010,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget name="infokey" position="1270,10" size="80,40" alphatest="on" />
		<widget name="menukey" position="1270,50" size="80,40" alphatest="on" />
		<widget name="gemfury" position="1380,12" size="228,72" alphatest="on" />
		<eLabel backgroundColor="grey" position="20,100" size="1600,2" />
		<eLabel backgroundColor="grey" position="20,940" size="1600,2" />
		<widget name="about" position="20,960" size="1600,60" halign="center" valign="center" foregroundColor="yellow" font="Regular;48" />
		<eLabel backgroundColor="grey" position="20,1040" size="1600,2" />
		<widget name="info" position="20,1060" size="1600,60" halign="center" valign="center" foregroundColor="yellow" font="Regular;40" />
		<widget name="text" position="30,130" size="1590,800" font="Regular;40" />
		</screen>"""
	else:
		skin = """
		<screen name="SvenH_Info" position="center,100" size="820,580" >
		<widget name="logo" position="10,5" size="100,40" />
		<widget backgroundColor="#9f1313" font="Regular;16" halign="center" name="buttonred" position="115,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget backgroundColor="#1f771f" font="Regular;16" halign="center" name="buttongreen" position="245,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget backgroundColor="#a08500" font="Regular;16" halign="center" name="buttonyellow" position="375,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget backgroundColor="#18188b" font="Regular;16" halign="center" name="buttonblue" position="505,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget name="infokey" position="635,5" size="40,20" alphatest="on" />
		<widget name="menukey" position="635,25" size="40,20" alphatest="on" />
		<widget name="gemfury" position="690,6" size="114,36" alphatest="on" />
		<eLabel backgroundColor="grey" position="10,50" size="800,1" />
		<eLabel backgroundColor="grey" position="10,470" size="800,1" />
		<widget name="about" position="10,480" size="800,30" halign="center" valign="center" foregroundColor="yellow" font="Regular;24"/>
		<eLabel backgroundColor="grey" position="10,520" size="800,1" />
		<widget name="info" position="10,530" size="800,30" halign="center" valign="center" foregroundColor="yellow" font="Regular;20"/>
		<widget name="text" position="15,65" size="795,400" font="Regular;20"/>
		</screen>"""

	def __init__(self, session, title, header, footer, package, package_status, localdeb, feedname):
		Screen.__init__(self, session)
		self.title=title + " (" + feedname + ")"
		self.header=header
		self.footer=footer
		self.package=package
		self.package_status=package_status
		self.localdeb=localdeb
		self.feedname=feedname
		self.aptresult=""

		cprint("title %s header %s footer %s package %s package_status %s localdeb %s" %  (self.title,self.header, self.footer, self.package, self.package_status, self.localdeb))
		self.onShown.append(self.setWindowTitle)
		self["buttonred"] = Label(_("Exit"))
		self["buttongreen"] = Label(_("Changelog"))
		self["buttonyellow"] = Label("Copyright")
		self["buttonblue"] = Label("README")
		self["menukey"] = Pixmap()
		self["infokey"] = Pixmap()
		self["logo"] = Pixmap()
		self["about"] = Label(self.header)
		self["info"] = Label(self.footer)
		self["gemfury"] = Pixmap()
		self["text"] = ScrollLabel()
		HelpableScreen.__init__(self)
		self["colorActionsInfo"] = HelpableActionMap(self, "ColorActions",
				{
				"red": (self.cancel,_("Exit")),
				"green": (self.greenPressed,_("Changelog")),
				"yellow": (self.yellowPressed,_("Copyright")),
				"blue": (self.bluePressed,_("README")),
				}, -2)
		self["setupActionsInfo"] = HelpableActionMap(self, "SetupActions",
				{
				"cancel": (self.cancel,_("Exit")),
				}, -2)
		self["directionActionsInfo"] = HelpableActionMap(self, "DirectionActions",
				{
				"up": (self["text"].pageUp,_("Up")),
				"down": (self["text"].pageDown,_("Down")),
				"left": (self["text"].pageUp,_("Up")),
				"right": (self["text"].pageDown,_("Down")),
				}, -2)
		self["channelSelectBaseActionsInfo"] = HelpableActionMap(self, "ChannelSelectBaseActions",
				{
				"nextBouquet": (self.firstPage,_("Begin")),
				"prevBouquet": (self["text"].lastPage,_("End")),
				}, -2)
		self["channelSelectActionsInfo"] = HelpableActionMap(self, "ChannelSelectEPGActions",
				{
				"showEPGList": (self.infoPressed,_("show Checksum information")),
				}, -2)
		text_menu=_("select menu options")
		self["menuActionsInfo"] = HelpableActionMap(self, "MenuActions",
				{
				"menu": (self.menuPressed,text_menu),
				}, -2)
		# for new RC use Audio key as Help key alternative
		self["InfobarAudioSelectionActionsInfo"] = HelpableActionMap(self,"InfobarAudioSelectionActions",
				{
				"audioSelection": (self.audioPressed,_("show Help screen")),
				}, -3)
			
	def firstPage(self):
		cprint(">>> firstPage")
		self["text"].long_text.move(ePoint(0,0))
		self["text"].updateScrollbar()

	def audioPressed(self):
		audio2Help()

	def setWindowTitle(self):
		self.setTitle(self.title)
		self["logo"].instance.setPixmapFromFile("%s/plugin.png" % plugindir)
		self["gemfury"].instance.setPixmapFromFile("%s/gemfury.png" % plugindir)
		self["menukey"].instance.setPixmapFromFile(getPiconPath("menu"))
		self["infokey"].instance.setPixmapFromFile(getPiconPath("info"))
		if len(self.aptresult)==0:
			self.greenPressed() #load changelog

	def menuPressed(self):
		cprint(">>> menuPressed")
		self.aptresult="apt"
		list = []
		list.append(("show", "apt-cache show %s" % self.package))
		list.append(("depends", "apt-cache depends %s" % self.package))
		list.append(("rdepends", "apt-cache rdepends %s" % self.package))
		list.append(("list", "apt list %s" % self.package))
		list.append(("stats", "apt-cache stats"))
		list.append(("policy", "apt-cache policy"))
		self.session.openWithCallback(
				self.menuCallback,
				ChoiceBox,
				title = _("Following tasks will be done after you press OK!").replace("!",":"),
				windowTitle = getTitle(),
				list = list,
		)

	def menuCallback(self, command):
		if command is None:
			return
		else:
			cmd=command[1]
			self.aptresult="%s:\n\n" % cmd
			cprint("apt cmd: %s" % cmd)
			self.aptcontainer = eConsoleAppContainer()
			self.aptcontainer.dataAvail_conn = self.aptcontainer.dataAvail.connect(self.aptDataAvailable)
			self.aptcontainer.appClosed_conn = self.aptcontainer.appClosed.connect(self.aptCacheFinished)
			self.aptcontainer.execute(cmd)

	def aptDataAvailable(self,str):
		cprint(">>>> %s" % str)
		if str.find("WARNING:") is -1:
			self.aptresult+=str

	def aptCacheFinished(self,ret):
		cprint(self.aptresult)
		self["text"].setText(self.aptresult)

	def infoPressed(self):
		self.aptresult=""
		cprint(">>> infoPressed")
		md5sums = ""
		if self.localdeb and self.package_status in (INSTALLABLE, INSTALLED):
			name,desc,deb,status,new,depends,md5sums = parseDeb(os_path.dirname(self.localdeb),os_path.basename(self.localdeb))
		if not md5sums:
			local="/var/lib/dpkg/info/%s.md5sums" % self.package
			if os_path.exists(local):
				f=open(local,"r")
				md5sums=f.read()
				f.close()

		if md5sums:
			if self.package_status in (INSTALLED, UPDATENEEDED, DOWNGRADE):
				#check for md5 only if local deb-status is installed
				mds5entries = md5sums.strip("\n").split("\n")
				md5ok_list = []
				md5fail_list = []
				for md5entry in mds5entries:
					pos = md5entry.find(" ")
					if pos:
						md5hash = md5entry[:pos]
						file = md5entry[pos:].strip().strip("*")
						if not file.startswith("/"):
							file="/"+file
						if os_path.exists(file):
							md5fromFile = hashlib.md5(open(file,'rb').read()).hexdigest()
						else:
							md5fromFile = ""
						if md5fromFile == md5hash:
							md5ok_list.append(md5hash + " " + file)
						else:
							md5fail_list.append(md5hash + " " + file)

				text=""
				if md5fail_list:
					text+=_("md5sum check failure")+":\n\n" + "\n".join(md5fail_list)+"\n"
				if md5ok_list:
					if len(text) > 0:
						text+="\n"
					text +=_("md5sum check ok") + ":\n\n" + "\n".join(md5ok_list) + "\n"
				self["text"].setText(text)
			else:
				self["text"].setText(_("md5sums from DEB-package:") +"\n"+ md5sums)
		else:
			self["text"].setText(_("md5sums: not found"))

	def finishedDownload(self, file):
		cprint(">>> finishedDownload")
		first_search_string = '<pre><em>'
		pos0 = file.find(first_search_string)
		#cprint(">>> file %s" % file)
		if pos0 > 0:
			cprint(">>> find pre em")
			pos1 = file.find("</em></pre>",pos0)
			text = file[pos0 + len(first_search_string):pos1]
			text = re_sub("^<!--%\+b:..%-->","",text)
			text = re_sub("<!--%-b:..%-->$","",text)
			text = text.replace("&lt;","<").replace("&gt;",">")
		else:
			cprint(">>> second try")
			first_search_string = '<!--%\+b:..%--><!--%glmr%--><pre class="chroma"><code>'
			second_search_string = '</code></pre><!--%glmr%--><!--%-b:..%-->'
			pos0=-1
			match = re_search(first_search_string, file)
			if match: pos0 = match.start()
			if pos0>0:
				cprint(">>> find by second try")
				pos1=0
				match = re_search(second_search_string, file)
				if match: pos1 = match.start()
				text = file[pos0 + len(first_search_string)-1:pos1]
				text = re_sub(r'<.*?>', '', text) # remove html tags
				text = text.replace("&lt;","<").replace("&gt;",">").strip()
			else:
				cprint(">>> not found in text")
				text = "text not found"
		#cprint("text: %s" % text)
		self["text"].setText(text)

	def failedDownload(self, error):
		cprint(">>> failedDownload error: %s" % error)
		dir = "/usr/share/doc/%s" % (self.package)
		name = self.fileName.lower()
		#cprint("dir: %s lower: %s" % (dir,name))
		found=False
		if os_path.exists(dir) and not (self.localdeb and self.package_status in (INSTALLABLE, UPDATENEEDED)):
			for file in os_listdir(dir):
				filel=file.lower()
				if filel.startswith(name):
					found=True
					gotit=dir+"/"+file
					if file.endswith(".gz"):
						f=gzip.open(gotit,"rb")
					else:
						f=open(gotit,"r")
					text=f.read()
					f.close()
					self["text"].setText(text)
		elif self.localdeb: # load info from local deb file
			cprint("read file from local deb: %s" % self.localdeb)
			changelog,copyright,readme=parseDoc(os_path.dirname(self.localdeb),os_path.basename(self.localdeb))
			file=self.fileName.lower()
			found=True
			if file.startswith("readme") and readme:
				self["text"].setText(readme)
			elif file.startswith("changelog") and changelog:
				self["text"].setText(changelog)
			elif file.startswith("copyright") and copyright:
				self["text"].setText(copyright)
			else:
				self["text"].setText(file + ": " + _("No details found."))
		elif self.package_status in (INSTALLED,) and self.downloadCount == 0:
			#if installed, but not found in /usr/share/doc/...package... then load from gemfury
			self.downloadCount=1
			self["text"].setText(_("Downloading")+" %s ..." % self.fileName)
			url = "https://gemfury.com/%s/deb:%s/-/content/usr/share/doc/%s/%s" % (plugin_feedName, self.package, self.package, self.fileName)
			cprint("downloading: %s" % url)
			self.fileDownloader = fileDownloader(url)
			self.fileDownloader.getList(self.finishedDownload, self.failedDownload)
			return

		if not found:
			self["text"].setText(_("Download failed")+": %s\n\n%s" % (self.fileName, error))

	def startDownload(self, fileName):
		self.fileName = fileName
		self.downloadCount=0
		cprint("package status: %s" % self.package_status)
		if self.package_status in (INSTALLABLE, UPDATENEEDED) and not self.localdeb:
			self["text"].setText(_("Downloading")+" %s ..." % fileName)
			url = "https://gemfury.com/%s/deb:%s/-/content/usr/share/doc/%s/%s" % (plugin_feedName, self.package, self.package, self.fileName)
			cprint("downloading: %s" % url)
			self.fileDownloader = fileDownloader(url)
			self.fileDownloader.getList(self.finishedDownload, self.failedDownload)
		else:
			self.failedDownload(_("An empty filename is illegal."))

	def greenPressed(self):
		self.aptresult=""
		cprint(">>> greenPressed")
		self.startDownload("changelog")

	def yellowPressed(self):
		self.aptresult=""
		cprint(">>> yellowPressed")
		self.startDownload("copyright")

	def bluePressed(self):
		self.aptresult=""
		cprint(">>> bluePressed")
		self.startDownload("README")

	def cancel(self):
		self.close(False)

def metaDreamy(enable_meta=True):
	try:
		packagesList = getPackagesList(getAll=True)
		for packagename in packagesList:
			autor="Sven H"
			cprint("metaDream packagename %s, %s" % (autor, packagename))
			global statusfile_data
			statusfile_data = ""
			gp4_filter = ""
			gp4_filename = "/etc/enigma2/AddonFilterlist_%s.json" % autor
			if not os_path.exists(packagename):
				cprint("no Packages file (yet)")
				if not enable_meta:
					removeStrandedMetas(autor)
				continue
			cprint("meta file creation: %s" % enable_meta)
			f = open(packagename,"r")
			content = f.read()
			f.close()
			if len(content) == 0:
				continue
			content=content.replace("\n ",",, ").replace("\n ",",, ") #replace ENTER in description
			packages=content.strip().split("\n\n")
			#checkPreview_value = checkPreview()
			for package in packages:
				#create meta-files
				package_list = package.strip("\n").split("\n")
				try:
					package = dict([(x.split(":")[0].strip(),x.split(":")[1].strip()) for x in package_list])
				except:
					cprint("BAD package file: %s" % packagename)
					return
				
				if enable_meta:
					desc=package['Description'].replace(",,","") #remove replaced ENTER
					sp=desc.split(" ")
					if len(sp)>1:
						name="%s %s" % (sp[0],sp[1])
					else:
						name=sp[0]
					if name != desc:
						shortdesc = desc.replace(name,"")
					else:
						shortdesc = name
					longdesc = shortdesc
					
					meta_txt  = '<default>\n'
					meta_txt += '\t<prerequisites>\n'
					meta_txt += '\t\t<tag type="%s" />\n' % autor
					meta_txt += '\t</prerequisites>\n'
					meta_txt += '\t<info>\n'
					meta_txt += '\t\t<author>%s</author>\n' % autor
					meta_txt += '\t\t<name>%s</name>\n' % name
					meta_txt += '\t\t<packagename>%s</packagename>\n' % package['Package']
					if config.plugins.svenh.size.value:
						size=int(package['Size'])//1024
						shortdescription="%s - %dkB" % (shortdesc,size)
						longdescription="%s - %dkB" % (longdesc,size)
					else:
						shortdescription=shortdesc
						longdescription=longdesc
					if config.plugins.svenh.version.value:
						current=currentVersion(package['Package'])
						new=package['Version'].strip()
						if new==current or current==_("none"):
							meta_txt += '\t\t<shortdescription>%s %s</shortdescription>\n' % (shortdescription, new)
							meta_txt += '\t\t<description>%s %s</description>\n' % (longdescription, new)
						else:
							meta_txt += '\t\t<shortdescription>%s %s %s %s</shortdescription>\n' % (shortdescription, current, _("Update"), package['Version'])
							meta_txt += '\t\t<description>%s %s %s %s</description>\n' % (longdescription, current, _("Update"), package['Version'])
					else:
						meta_txt += '\t\t<shortdescription>%s</shortdescription>\n' % shortdescription
						meta_txt += '\t\t<description>%s</description>\n' % longdescription
					meta_txt += '\t</info>\n'
					meta_txt += '\t<files type="package"> <!-- without version, without .ipk -->\n'
					meta_txt += '\t\t<file type="package" name="%s" />\n' % package['Package']
					meta_txt += '\t</files>\n'
					meta_txt += '</default>\n'

				meta_filename = "/usr/share/meta/plugin_%s_%s.xml" % (autor, package['Package'].split("-")[-1].lower())
				if enable_meta:
					writeMeta(meta_filename, meta_txt)
				else:
					removeMeta(meta_filename)

				#set all packages as filter-text for AddonFilter_Sven H.json
				if gp4_filter:
					gp4_filter += "," + package['Package']
				else:
					gp4_filter = package['Package']
			
			if enable_meta:
				# write gp4 json
				gp4Write(gp4_filename,gp4_filter,autor)
				pass
			else:
				gp4Remove(gp4_filename,autor)
				removeStrandedMetas(autor)
	except:
		cprint("error on write meta")

def removeStrandedMetas(autor):
		# check for stranded metas of plugins from feed
		for file in os_listdir("/usr/share/meta"):
			f=open("/usr/share/meta/%s" % file)
			mm=f.read()
			f.close()
			if mm.find(autor) != -1:
				cprint("remove stranded meta file %s" % file)
				os_remove("/usr/share/meta/%s" % file)
	

def checkApt(kill=False):
	pids = [pid for pid in os_listdir('/proc') if pid.isdigit()]
	apt=False
	for pid in pids:
		try:
			cmd=open(os_path.join('/proc', pid, 'cmdline'), 'rb').read().split('\0')
			if cmd[0].find("apt") != -1:
				apt=True
				if kill:
					os_kill(int(pid), signal.SIGKILL)
		except IOError: # proc has already terminated
			continue
	return apt

def checkHost(url):
	host=url[url.find("//")+2:]
	sp=[]
	sp=host.split(":")
	host=sp[0]
	sp=host.split("/")
	host=sp[0]
	if "@" in host:
		host = host.split("@")[1]
	resolv=None
	try:
		resolv=gethostbyname(host)
	except:
		cprint("HOST ERROR %s" % host)
	if resolv==host:
		resolv=None
	return host, resolv

def currentVersion(package, feedDeb=True):
	global statusfile_data
	if len(statusfile_data) == 0:
		cprint("reading %s" % plugin_status_file)
		statusfile_data=open(plugin_status_file,"r").read().split("\n")
	needle="Package: %s" % package
	needle=needle.strip()
	version=_("none")
	try:
		if needle in statusfile_data:
			index = statusfile_data.index(needle)
			status_line = statusfile_data[index+1]
			if status_line.startswith(("Status: deinstall ok","Status: install ok not-installed")):
				return version
			for line in statusfile_data[index+1:]:
				if line.startswith("Version:"):
					sp=line.split(":")
					if len(sp) > 1:
						version=sp[1].strip()
					cprint("got Version %s for %s" % (version,package))
					if feedDeb and package==feedPlugin_PackageName:
						for line in statusfile_data[index+1:]:
						# cprint(">>>>>>>>>>>>> %s" % line)
							if line.startswith("Date:"):
								sp=line.split(":")
								if len(sp) > 1:
									date=sp[1].strip()
								sp=date.split()
								ymd="%s%s%02d" % (sp[3],abbr_to_num(sp[2]),int(sp[1]))
								version=version+"-"+ymd
								return version
					return version
		return version
	except:
		import traceback, sys
		traceback.print_exc()
		return version

def writeMeta(meta_filename, meta_text):
	if os_path.exists(meta_filename):
		f = open(meta_filename, "r")
		old_text=f.read()
		f.close()
		if old_text == meta_text:
			#cprint("meta file %s unchanged" % meta_filename)
			return
	# new meta file or content changed ...
	open(meta_filename, "w")
	f = open(meta_filename, "w")
	f.write(meta_text)
	f.close()
	cprint("meta file %s written" % meta_filename)

def removeMeta(meta_filename):
	if os_path.exists(meta_filename):
		os_remove(meta_filename)
		cprint("meta file %s removed" % meta_filename)

def gp4Write(gp4_filename,gp4_filter,autor):
	cprint("gp4Write: %s, %s " % (gp4_filename, gp4_filter))
	#create AddonFilter_Sven H.json file for the AddonManager if the user file exists
	gp4_userfilename = "/etc/enigma2/AddonFilterlistuser.json"
	if os_path.exists(gp4_userfilename):
		gp4_name = autor + " - " + _("Plugins")
		gp4_hide = 0
		gp4_sort = 1
		gp4_desc = "%s - %s" % (autor,_("Plugin selection"))
		gp4_json_txt = '{\n\t"entrys": [\n\t{"name":"%s", "hide":%s, "sort":%s, "desc":"%s", "filter":"%s"}\n\t]\n}\n' % (gp4_name, gp4_hide, gp4_sort, gp4_desc, gp4_filter)
		#cprint("gp4: %s" % gp4_json_txt)
		if os_path.exists(gp4_filename):
			f = open(gp4_filename, "r")
			old_json=f.read()
			f.close()
			if old_json != gp4_json_txt:
				cprint("re-writing file: %s" % gp4_filename)
				f= open(gp4_filename, "w")
				f.write(gp4_json_txt)
				f.close()
		else:
			cprint("creating file: %s" % gp4_filename)
			f= open(gp4_filename, "w")
			f.write(gp4_json_txt)
			f.close()

		lines = open(gp4_userfilename).readlines()
		for line in lines:
			if line.find(autor + " ") != -1:
				#read value for hide/sort
				gp4_komma = ""
				if line.strip("\n").endswith(","):
					gp4_komma = ","
				line_attribs = line.split(",")
				for attr in line_attribs:
					attr = attr.split(":")
					if '"hide"' in attr[0]:
						gp4_hide = int(attr[1])
					if '"sort"' in attr[0]:
						gp4_sort = int(attr[1])
				gp4_json_line = '\t{"name":"%s", "hide":%s, "sort":%s, "desc":"%s", "filter":"%s"}%s\n' % (gp4_name, gp4_hide, gp4_sort, gp4_desc,gp4_filter, gp4_komma)
				if line != gp4_json_line:
					# remove from AddonFilterlistuser.json to reload
					# the new AddonFilterlist_Sven H.json in GP4 AddonManager
					cprint("refresh %s line in %s" % (autor, gp4_userfilename))
					lines[lines.index(line)] = gp4_json_line
					gp4_json_txt = "".join(lines).replace(",\n\t]","\n\t]") #replace ',' on last entry
					f = open(gp4_userfilename, "w")
					f.write(gp4_json_txt)
					f.close()
					break

def gp4Remove(gp4_filename,autor):
	cprint("gp4remove: %s" % gp4_filename)
	if os_path.exists(gp4_filename):
		os_remove(gp4_filename)
	gp4_userfilename = "/etc/enigma2/AddonFilterlistuser.json"
	if os_path.exists(gp4_userfilename):
		lines = open(gp4_userfilename).readlines()
		for line in lines:
			if line.find(autor + " ") != -1:
				cprint("remove %s line in %s" % (autor, gp4_userfilename))
				lines.remove(line)
				gp4_json_txt = "".join(lines).replace(",\n\t]","\n\t]") #replace if ',' after last entry
				f = open(gp4_userfilename, "w")
				f.write(gp4_json_txt)
				f.close()
				break

class SvenH_DirectoryBrowser(Screen):
	if sz_w == 1920:
		skin = """
		<screen name="SvenH_DirectoryBrowser" position="center,170" size="920,740">
				<ePixmap pixmap="Default-FHD/skin_default/buttons/red.svg" position="10,5" size="300,70" />
				<ePixmap pixmap="Default-FHD/skin_default/buttons/green.svg" position="310,5" size="300,70" />
				<widget backgroundColor="#9f1313" font="Regular;30" halign="center" position="10,5" render="Label" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="300,70" source="key_red" transparent="1" valign="center" zPosition="1" />
				<widget backgroundColor="#1f771f" font="Regular;30" halign="center" position="310,5" render="Label" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="300,70" source="key_green" transparent="1" valign="center" zPosition="1" />
				<eLabel backgroundColor="grey" position="10,80" size="900,1" />
				<widget enableWrapAround="1" name="filelist" position="10,90" scrollbarMode="showOnDemand" size="900,630" />
		</screen>"""
	elif sz_w == 2560:
		skin = """
		<screen name="SvenH_DirectoryBrowser" position="center,240" size="1220,860" >
				<ePixmap pixmap="skin_default/buttons/red.png" position="20,10" size="400,80" />
				<ePixmap pixmap="skin_default/buttons/green.png" position="420,10" size="400,80" />
				<widget source="key_red" render="Label" position="20,10" size="400,80" zPosition="1" font="Regular;40" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" />
				<widget source="key_green" render="Label" position="420,10" size="400,80" zPosition="1" font="Regular;40" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" />
				<eLabel position="20,100" size="1180,2" backgroundColor="grey" />
				<widget name="filelist" position="20,120" size="1180,720" enableWrapAround="1" scrollbarMode="showOnDemand" />
		</screen>"""
	else:
		skin = """
		<screen name="SvenH_DirectoryBrowser" position="center,120" size="610,430">
				<ePixmap pixmap="skin_default/buttons/red.png" position="10,5" size="200,40"/>
				<ePixmap pixmap="skin_default/buttons/green.png" position="210,5" size="200,40"/>
				<widget source="key_red" render="Label" position="10,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2"/>
				<widget source="key_green" render="Label" position="210,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2"/>
				<eLabel position="10,50" size="590,1" backgroundColor="grey"/>
				<widget name="filelist" position="10,60" size="590,360" enableWrapAround="1" scrollbarMode="showOnDemand"/>
		</screen>"""

	def __init__(self, session, text = "", filename = "", currDir = None, bookmarks = None, userMode = False, windowTitle = _("Select Location"), minFree = None, autoAdd = False, editDir = False, inhibitDirs = [], inhibitMounts = []):
		Screen.__init__(self, session)
		if currDir and not os_path.exists(currDir):
			currDir = "/"
		if not currDir.endswith("/"):
			currDir += "/"

		self.filelist = FileList(currDir, showDirectories = True, showFiles = False, inhibitMounts = inhibitMounts, inhibitDirs = inhibitDirs)
		self["filelist"] = self.filelist
		self["filelist"].onSelectionChanged.append(self.selectionChanged)

		self["FilelistActions"] = ActionMap(["SetupActions"],
				{
						"save": self.select,
						"ok": self.ok,
						"cancel": self.exit
				})
		self["key_red"] = StaticText(_("Cancel"))
		self["key_green"] = StaticText(_("OK"))

		self.windowTitle = windowTitle
		self.onShown.append(self.setWindowTitle)

	def setWindowTitle(self):
		self.setTitle(self.windowTitle)

	def ok(self):
		if self["filelist"].canDescent(): # isDir
			self["filelist"].descent()

	def select(self):
		directory = self["filelist"].getSelection()[0]
		if directory != "/":
			directory = directory.rstrip("/")
		self.close(directory)

	def selectionChanged(self):
		pass

	def exit(self):
		self.close(None)

class SvenH_Setup(Screen, ConfigListScreen, HelpableScreen):
	if sz_w == 1920:
		skin = """
		<screen name="SvenH_Setup" position="center,170" size="1200,890">
		<widget name="logo" position="20,10" size="150,60" />
		<widget backgroundColor="#9f1313" font="Regular;26" halign="center" name="buttonred" position="180,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget backgroundColor="#1f771f" font="Regular;26" halign="center" name="buttongreen" position="370,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget backgroundColor="#a08500" font="Regular;26" halign="center" name="buttonyellow" position="560,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget backgroundColor="#18188b" font="Regular;26" halign="center" name="buttonblue" position="750,10" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="180,60" valign="center" />
		<widget name="gemfury" position="1002,12" size="177,56" alphatest="on" />
		<widget name="info" position="935,10" size="60,30" alphatest="on" />
		<widget name="menu" position="935,40" size="60,30" alphatest="on" />
		<eLabel backgroundColor="grey" position="20,90" size="1160,1" />
		<widget name="config" enableWrapAround="1" position="30,110" scrollbarMode="showOnDemand" size="1140,670" />
		<eLabel backgroundColor="grey" position="20,790" size="1160,1" />
		<widget name="text" backgroundColor="background" position="40,800" size="1120,80" font="Regular;28" zPosition="1" transparent="1"/>
		</screen>"""
	elif sz_w == 2560:
		skin = """
		<screen name="SvenH_Setup" position="center,200" size="1640,1160" >
		<widget name="logo" position="20,10" size="200,80" />
		<widget backgroundColor="#9f1313" font="Regular;32" halign="center" name="buttonred" position="230,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget backgroundColor="#1f771f" font="Regular;32" halign="center" name="buttongreen" position="490,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget backgroundColor="#a08500" font="Regular;32" halign="center" name="buttonyellow" position="750,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget backgroundColor="#18188b" font="Regular;32" halign="center" name="buttonblue" position="1010,10" foregroundColor="white" shadowColor="black" shadowOffset="-4,-4" size="240,80" valign="center" />
		<widget name="gemfury" position="1380,12" size="228,72" alphatest="on" />
		<widget name="info" position="1270,10" size="80,40" alphatest="on" />
		<widget name="menu" position="1270,50" size="80,40" alphatest="on" />
		<eLabel backgroundColor="grey" position="20,100" size="1600,2" />
		<widget name="config" position="30,120" size="1580,840" enableWrapAround="1" scrollbarMode="showOnDemand" />
		<eLabel backgroundColor="grey" position="20,980" size="1600,2" />
		<widget name="text" backgroundColor="background" position="40,1000" size="1560,140" font="Regular;44" zPosition="1" transparent="1" />
		</screen>"""
	else:
		skin = """
		<screen name="SvenH_Setup" position="center,100" size="820,580">
		<widget name="logo" position="10,5" size="100,40" />
		<widget backgroundColor="#9f1313" font="Regular;16" halign="center" name="buttonred" position="115,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget backgroundColor="#1f771f" font="Regular;16" halign="center" name="buttongreen" position="245,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget backgroundColor="#a08500" font="Regular;16" halign="center" name="buttonyellow" position="375,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget backgroundColor="#18188b" font="Regular;16" halign="center" name="buttonblue" position="505,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="120,40" valign="center" />
		<widget name="gemfury" position="690,6" size="114,36" alphatest="on" />
		<widget name="info" position="635,5" size="40,20" alphatest="on" />
		<widget name="menu" position="635,25" size="40,20" alphatest="on" />
		<eLabel backgroundColor="grey" position="10,50" size="800,1" />
		<widget name="config" position="15,60" size="790,420" enableWrapAround="1" scrollbarMode="showOnDemand" />
		<eLabel backgroundColor="grey" position="10,490" size="800,1" />
		<widget name="text" backgroundColor="background" position="20,500" size="780,70" font="Regular;22" zPosition="1" transparent="1"/>
		</screen>"""

	def __init__(self, session, args = 0):
		Screen.__init__(self, session)
		self.list = []
		# explizit check on every entry
		self.onChangedEntry = []
		self.onConfigEntryChanged = []
		ConfigListScreen.__init__(self, self.list, session = self.session, on_change = self.changedEntry)
		self["config"].onSelectionChanged.append(self.selectionChanged)
		self.createSetup()
		
		self["buttonred"] = Label(_("Exit"))
		self["buttongreen"] = Label(_("Save"))
		self["buttonyellow"] = Label(_("Reset"))
		self["buttonblue"] = Label(_("About"))
		self["text"] = Label()
		self["logo"] = Pixmap()
		self["menu"] = Pixmap()
		self["info"] = Pixmap()
		self["gemfury"] = Pixmap()
		
		self["setupActions"] = ActionMap(["ColorActions","SetupActions","EPGSelectActions","MenuActions"],
			{
			"red":    self.redPressed,
			"green":  self.save,
			"yellow": self.yellowPressed,
			"blue":   self.about,
			"save":   self.save,
			"cancel": self.redPressed,
			"ok":     self.okPressed,
			"info":   self.about,
			"menu":   self.redPressed,
			}, -2)
		
		self.onLayoutFinish.append(self.onLayoutFinished)

	def onLayoutFinished(self):
		self.setTitle(getTitle() + " v%s" % plugin_version + " - " + _("Setup") )
		self["logo"].instance.setPixmapFromFile("%s/plugin.png" % plugindir)
		self["gemfury"].instance.setPixmapFromFile("%s/gemfury.png" % plugindir)
		self["menu"].instance.setPixmapFromFile(getPiconPath("menu"))
		self["info"].instance.setPixmapFromFile(getPiconPath("info"))

	def selectionChanged(self):
		cur = self["config"].getCurrent()
		if cur:
			self["text"].text = cur[2]

	def about(self):
		self.session.open(MessageBox, _("Feed Plugin v%s by Sven H (2022)") % plugin_version, MessageBox.TYPE_INFO, timeout=plugin_timeout)

	def save(self):
		config.plugins.svenh.package_install.value=config.plugins.svenh.package_install.default
		config.plugins.svenh.package_uninstall.value=config.plugins.svenh.package_uninstall.default
		config.plugins.svenh.package_update.value=config.plugins.svenh.package_update.default
		config.plugins.svenh.package_downgrade.value=config.plugins.svenh.package_downgrade.default
		for x in self["config"].list:
			if len(x) > 1:
				x[1].save()
		configfile.save
		self.close(True)

	def cancel(self,answer):
		if answer:
			for x in self["config"].list:
				if len(x) > 1:
					x[1].cancel()
			cprint("direct close")
			self.close(False)

	def yellowPressed(self):
		self.session.openWithCallback(self.callbackReset,MessageBox,_("Reset to defaults?"))

	def callbackReset(self, ret):
		if ret:
			for x in self["config"].list:
				if len(x) > 1:
					x[1].value = x[1].default
			self.createSetup()

	def redPressed(self):
		changed=self["config"].isChanged()
		if changed and config.plugins.svenh.confirm.value!="false":
			if config.plugins.svenh.confirm.value=="true":
				text=_("Really close without saving settings?")
				self.session.openWithCallback(self.cancel,MessageBox,text,MessageBox.TYPE_YESNO)
			else:   # only info message ...
				text=_("Close without saving settings!")
				self.session.openWithCallback(self.cancel,MessageBox,text,MessageBox.TYPE_WARNING)
		elif changed:
			self.cancel(True)
		else:
			self.close(False)

	def changedEntry(self):
		cprint(">>>> changedEntry")
		cur = self["config"].getCurrent()[1]
		self.createSetup()

	def createSetup(self, first=False):
		self.list = []
		self.list.append(getConfigListEntry(_("activate feed"), config.plugins.svenh.feed,_("Activate or deactivate the feed-function of this plugin.\nIf deactivated no plugins from feeds will be listed.")))
		self.list.append(getConfigListEntry(_("Install local plugins"), config.plugins.svenh.local,_("Activate or deactivate the package-listing from selectable local folder.\nYou can use predefined folders or a userdefined folder.")))
		
		if config.plugins.svenh.local.value == "user":
			self.list.append(getConfigListEntry("..." + _("User defined folder for local install"), config.plugins.svenh.local_user_path,_("You can select a local folder with 'OK'.")))
		
		if config.plugins.svenh.feed.value or config.plugins.svenh.local.value != "none":
			ask_text=_("yes: The plugin will ask you before starting package-actions.\nMessage: The plugin only shows a message on package-actions.")
			self.list.append(getConfigListEntry(_("Ask user"), config.plugins.svenh.confirm,ask_text))
			self.list.append(getConfigListEntry(_("show package version"), config.plugins.svenh.version,_("Show the current version number of the package in the package list.")))
			self.list.append(getConfigListEntry(_("show package size"), config.plugins.svenh.size,_("Show the size of the package in the package list.")))
			extra_text=_("Select the extra info is shown in the package list (default=description).")
			self.list.append(getConfigListEntry(_("show extra info"), config.plugins.svenh.show_info,extra_text))
			self.list.append(getConfigListEntry(_("show section with updates"), config.plugins.svenh.show_update_section,_("Show an additional section on the top of the package list for updatable packackes.")))
			self.list.append(getConfigListEntry(_("sort the package list"), config.plugins.svenh.listview,_("Select the sorting mode of the package list.")))
		
		self["config"].list = self.list
		self["config"].l.setList(self.list)

	def okPressed(self):
		if self["config"].getCurrent()[1] == config.plugins.svenh.local_user_path:
			self.openDirectoryBrowser(config.plugins.svenh.local_user_path.value)
			return

	def openDirectoryBrowser(self, path):
		try:
			self.session.openWithCallback(
				self.openDirectoryBrowserCB,
				SvenH_DirectoryBrowser,
					windowTitle = _("Choose Directory:"),
					currDir = str(path),
					bookmarks = None,
					autoAdd = False,
					editDir = True,
					inhibitDirs = ["/.cache", "/.local", "/autofs","/bin", "/boot", "/dev", "/etc", "/home", "/lib", "/proc", "/run", "/sbin", "/sys", "/usr", "/var", "/mnt", "/media/net", "/net"],
					minFree = None )
		except Exception, e:
			cprint("openDirectoryBrowser get failed: %s" % str(e))

	def openDirectoryBrowserCB(self, path):
		if not path is None:
			if path != config.plugins.svenh.local_user_path.value:
				config.plugins.svenh.local_user_path.value = path