#!/usr/bin/env python

# This file is part of Window-Switch.
# Copyright (c) 2009-2013 Antoine Martin <antoine@nagafix.co.uk>
# Window-Switch is released under the terms of the GNU GPL v3

import os
import types
import stat
import re

from winswitch.consts import APPLICATION_NAME, WINSWITCH_VERSION, WINSWITCH_HOME_DIR, WINSWITCH_SERVER_SOCKET_PATH, WINSWITCH_SERVER_LOCK_DIR
from winswitch.globals import USER_ID, USERNAME, WIN32
from winswitch.util.paths import PORT_FILENAME, CLIENT_CONF, SERVER_CONF, LOCAL_SOCKET_NAME, SERVER_SOCKET_NAME, AUTHORIZED_KEYS_FILE, AVATAR_ICON_FILE, WINSWITCH_SHARE_DIR, PORTS_CONF
from winswitch.util.paths import WINSWITCH_DIR, SERVERS_DIR, TEMP_DIR, SESSION_DIR, XPRA_DIR, LIBVIRT_DIR, CLIENT_DIR, SERVER_DIR, COMMAND_ICONS_DIR, XMODMAP_DIR, EXPORTS_DIR, SESSION_TEMP_DIR
from winswitch.util.paths import GLOBAL_SERVER_DIR, GLOBAL_SERVER_STATE_DIR, MENU_DIR, ACTIONS_DIR, XSESSIONS_DIR, PROTOCOLS_DIR, LOCK_DIR, APP_DIR, SERVER_CONFIG_EXTENSION, GLOBAL_SERVER_LOG_DIR, SERVER_LOG
from winswitch.util.paths import SESSION_CONFIG_FILENAME, SESSION_CONFIG_EXT
from winswitch.util.common import get_bool, alphanumfile, load_binary_file, csv_list, is_valid_file, unquote
from winswitch.util.simple_logger import Logger, msig

logger=Logger("file_io", log_colour=Logger.CYAN)

VERSION_KEY = "winswitch_software_version"

RWXRWXRWX=511	#aka: 0777 or 0o777
RWX=448			#aka: 0700 or 0o700

def mksubdir(parent_dir, dir_name, mode=RWXRWXRWX):
	d = os.path.join(parent_dir, dir_name)
	if not os.path.exists(d):
		os.mkdir(d, mode)
	return d

def get_application_data_dir(user=USERNAME):
	path = None
	if WIN32:
		path = os.environ.get("APPDATA")
	else:
		if user==USERNAME:
			path = os.path.expanduser("~")
		else:
			path = os.path.expanduser("~%s" % user)			#does not work with python2.5 on win32?
	return path

def get_screen_socket_dir(user=USERNAME):
	return os.path.join("/var/run/screen", "S-%s" % user)

def get_xpra_dir(user=USERNAME):
	return mksubdir(get_application_data_dir(user), XPRA_DIR)

def get_libvirt_dir(user=USERNAME):
	return mksubdir(get_application_data_dir(user), LIBVIRT_DIR)

def get_app_dir(user=USERNAME):
	#allow env to override location:
	d = os.getenv(WINSWITCH_HOME_DIR)
	if d:
		return d
	return mksubdir(get_application_data_dir(user), WINSWITCH_DIR)

#
# Utility methods for creating directories on demand
#
def get_sub_dir(parent_dir, dir_name, as_root=False, mode=RWXRWXRWX):
	d = os.path.join(parent_dir, dir_name)
	if not as_root and not os.path.exists(d):
		logger.sdebug("directory %s does not exist, creating it" % d, parent_dir, dir_name, as_root, mode)
		try:
			os.mkdir(d, mode)
		except Exception, e:
			logger.serror("%s" % e, parent_dir, dir_name, as_root, mode)
	return d

def get_sub_app_dir(dir_name, user=USERNAME, mode=RWX):
	return get_sub_dir(get_app_dir(user), dir_name, mode=mode)

def get_temp_dir():
	return get_sub_app_dir(TEMP_DIR)


def _in_or_out_str(in_or_out):
	if in_or_out:	return	"soundin"
	else:			return	"soundout"

#
# Client files and directories
#
def get_client_dir(user=USERNAME):
	""" ~/.winswitch/client/ """
	return get_sub_app_dir(CLIENT_DIR, user, mode=RWX)
def get_client_sub_dir(dir_name, user=USERNAME, mode=RWXRWXRWX):
	""" ~/.winswitch/client/$dir_name """
	return get_sub_dir(get_client_dir(user), dir_name, mode=mode)

def get_client_config_filename(user=USERNAME):
	""" ~/.winswitch/client/client.conf """
	return os.path.join(get_client_dir(user), CLIENT_CONF)

def get_local_client_socket_path(user=USERNAME):
	""" ~/.winswitch/client/socket """
	return	os.path.join(get_client_dir(), LOCAL_SOCKET_NAME)

def get_servers_config_dir():
	""" ~/.winswitch/client/servers """
	return get_client_sub_dir(SERVERS_DIR)

def get_protocols_config_dir():
	""" ~/.winswitch/client/protocols """
	return get_client_sub_dir(PROTOCOLS_DIR)

def get_exports_config_dir():
	""" ~/.winswitch/client/exports """
	return get_client_sub_dir(EXPORTS_DIR)

def get_session_temp_dir():
	""" ~/.winswitch/client/sessions """
	return get_client_sub_dir(SESSION_TEMP_DIR)

def get_command_icons_dir():
	""" ~/.winswitch/client/command-icons """
	return get_client_sub_dir(COMMAND_ICONS_DIR)


#
# Session files stored on client
#
def get_client_session_dir(sessionID, user=USERNAME):
	""" client session files are stored in .winswitch/client/sessions/[SESSIONID]/ """
	return get_sub_dir(get_client_sub_dir(SESSION_DIR, user, RWX), sessionID)
def get_client_session_file(sessionID, user=USERNAME, filename="session", ext=""):
	return os.path.join(get_client_session_dir(sessionID, user), filename+ext)

def get_client_session_rdp_config_file(sessionID, sessionName, user=USERNAME):
	return get_client_session_file(sessionID, user, filename=sessionName, ext=".rdp")
def get_client_session_password_file(sessionID, user=USERNAME):
	return get_client_session_file(sessionID, user, ext=".pass")
def get_client_session_pid_file(sessionID, user=USERNAME):
	return get_client_session_file(sessionID, user, ext=".pid")
def get_client_session_log_file(sessionID, user=USERNAME):
	return get_client_session_file(sessionID, user, ext=".log")
def get_client_session_icon_file(sessionID, user=USERNAME):
	return get_client_session_file(sessionID, user, ext=".icon")
def get_client_session_sound_log_filename(sessionID, in_or_out, user=USERNAME):
	return get_client_session_file(sessionID, user, _in_or_out_str(in_or_out), ".log")

def get_authorized_keys_file(user=USERNAME):
	return	os.path.join(get_client_dir(user), AUTHORIZED_KEYS_FILE)

def get_avatar_icon_file(user=USERNAME):
	return	os.path.join(get_client_dir(user), AVATAR_ICON_FILE)

def pwd_get_user_id(username):
	import pwd
	pw = pwd.getpwnam(username)
	return	pw.pw_uid

try:
	import pwd
	assert pwd
	get_user_id = pwd_get_user_id
except:
	get_user_id = None


#
# Server files and directories
#
def get_server_dir(as_root=False):
	""" ~/.winswitch/server or /etc/winswitch when running as root """
	if USER_ID!=0 and not as_root:
		return get_sub_app_dir(SERVER_DIR, mode=RWX)
	if not as_root and not os.path.exists(GLOBAL_SERVER_DIR):
		os.mkdir(GLOBAL_SERVER_DIR)
	return GLOBAL_SERVER_DIR

def get_server_blocked_ports():
	if WIN32:
		return	os.path.join(APP_DIR, PORTS_CONF)
	return	os.path.join(get_server_dir(True), PORTS_CONF)

def get_server_sub_dir(dir_name, as_root):
	return get_sub_dir(get_server_dir(as_root), dir_name)

def get_local_server_config_filename(as_root=False):
	""" ~/.winswitch/server/server.conf or /etc/winswitch/server.conf when running as root """
	return os.path.join(get_server_dir(as_root), SERVER_CONF)

def get_local_server_socket(as_root=False):
	""" ~/.winswitch/server/socket or /var/lib/winswitch/socket when running as root """
	if USER_ID == 0 or as_root:
		return os.path.join(get_server_state_dir(as_root), SERVER_SOCKET_NAME)
	#allow env to override location:
	s = os.getenv(WINSWITCH_SERVER_SOCKET_PATH)
	if s:
		return	s
	return os.path.join(get_server_dir(as_root), SERVER_SOCKET_NAME)

def get_server_state_dir(as_root=False):
	""" ~/.winswitch/server or /var/lib/winswitch when running as root """
	if USER_ID!=0 and not as_root:
		return get_sub_app_dir(SERVER_DIR)
	if not as_root and not os.path.exists(GLOBAL_SERVER_STATE_DIR):
		os.mkdir(GLOBAL_SERVER_STATE_DIR)
	return GLOBAL_SERVER_STATE_DIR

def get_server_state_sub_dir(dir_name, as_root=False):
	return get_sub_dir(get_server_state_dir(as_root), dir_name, as_root, RWX)

def get_server_log_dir(as_root=False):
	""" ~/.winswitch/server or /var/log when running as root """
	if USER_ID!=0 and not as_root:
		return get_server_dir(as_root)
	return GLOBAL_SERVER_LOG_DIR

def get_server_log_filename(as_root=False):
	""" ~/.winswitch/server/server.log """
	return	os.path.join(get_server_log_dir(), SERVER_LOG)

def get_menu_dir(as_root=False):
	""" ~/.winswitch/server/menu """
	return get_server_sub_dir(MENU_DIR, as_root)
def get_actions_dir(as_root=False):
	""" ~/.winswitch/server/actions """
	return get_server_sub_dir(ACTIONS_DIR, as_root)
def get_xsessions_dir(as_root=False):
	""" ~/.winswitch/server/xsessions """
	return get_server_sub_dir(XSESSIONS_DIR, as_root)
def get_protocols_dir(as_root=False):
	""" ~/.winswitch/server/protocols """
	return get_server_sub_dir(PROTOCOLS_DIR, as_root)
def get_lock_dir(as_root=False):
	""" ~/.winswitch/server/lock """
	#allow env to override:
	ld = os.getenv(WINSWITCH_SERVER_LOCK_DIR)
	if ld:
		return	ld
	return get_server_state_sub_dir(LOCK_DIR, as_root)
def get_port_filename(as_root=False):
	""" ~/.winswitch/server/lock/port """
	return	os.path.join(get_lock_dir(as_root), PORT_FILENAME)
def get_xmodmap_dir(as_root=False):
	""" ~/.winswitch/server/xmodmap """
	return	get_server_state_sub_dir(XMODMAP_DIR, as_root)
def get_xmodmap_filename(uuid, as_root=False, is_modifiers=False):
	""" ~/.winswitch/server/xmodmap/$uuid.$ext """
	if is_modifiers:
		ext = "modifiers"
	else:
		ext = "keys"
	return	os.path.join(get_xmodmap_dir(), "%s.%s" % (uuid, ext))

#
# Session files stored on server
#
def get_sessions_dir(username, as_root=False):
	""" ~/.winswitch/server/sessions or /var/lib/winswitch/sessions when running as root """
	if as_root:
		d = get_server_state_sub_dir(SESSION_DIR, as_root)
		user_dir = os.path.join(d, username)
		if get_user_id:
			user_id = get_user_id(username)
			if not os.path.exists(user_dir):
				if USER_ID==0:
					os.mkdir(user_dir)
					os.chown(user_dir, user_id, 0)
					os.chmod(user_dir, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP)
				else:
					logger.serror("user directory '%s' does not exist" % user_dir, username, as_root)
		return	user_dir
	else:
		return get_server_state_sub_dir(SESSION_DIR, as_root)

def get_server_session_dir(display, username, as_root):
	dirname = display
	if display.startswith(":"):
		dirname = display[1:]
	return get_sub_dir(get_sessions_dir(username, as_root), dirname)

def do_get_session_filename(display, username, as_root, filename="session", ext=""):
	return os.path.join(get_server_session_dir(display, username, as_root), filename+ext)

def get_session_filename(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, SESSION_CONFIG_FILENAME, SESSION_CONFIG_EXT)
def get_session_icon_filename(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, ext=".icon")
def get_session_snapshot_filename(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, "snapshot", ".img")
def get_session_password_filename(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, ext=".pass")
def get_session_wrapper_log_filename(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, "command", ".log")
def get_session_pulseaudio_log_filename(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, "pulse", ".log")
def get_session_xmodmap_filename(display, username=USERNAME, as_root=False, is_modifiers=False):
	if is_modifiers:
		ext = "modifiers"
	else:
		ext = "keys"
	return do_get_session_filename(display, username, as_root, "xmodmap.%s" % ext)
def get_session_xauth_filename(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, "xauth")
def get_server_session_sound_log_filename(display, user_id, in_or_out, username=USERNAME, as_root=False):
	""" ~/.winswitch/server/sessions/$DISPLAY/sound[in|out]-$user_id.log """
	return do_get_session_filename(display, username, as_root, "%s-%s" % (_in_or_out_str(in_or_out), user_id), ".log")
def get_session_cupsd_config_filename(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, "cupsd", ".conf")
def get_session_cupsd_socket_filename(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, "cupsd", ".socket")
def get_session_cupsd_temp_dir(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, "cupsd", ".tmp")
def get_session_cupsd_log_filename(display, username=USERNAME, as_root=False):
	return do_get_session_filename(display, username, as_root, "cupsd", ".log")


def get_server_config_filename(config):
	if config.name:	filename = "%s-" % config.name
	else:			filename = ""
	if config.ID:	filename += config.ID
	else:			filename += "%s:%s" % (config.host, config.port)
	filename += SERVER_CONFIG_EXTENSION
	return os.path.join(get_servers_config_dir(), alphanumfile(filename))

def get_server_hostkey_filename(server):
	if not server or not server.ID:
		return	None
	return os.path.join(get_servers_config_dir(), "%s.hostkey" % server.ID)

def get_server_signatureimage_filename(server):
	if not server or not server.ID:
		return	None
	return os.path.join(get_servers_config_dir(), "%s-signature.png" % server.ID)

def get_ssh_server_control_path(server, withX):
	ext = "controlpath"
	if withX:
		ext = "X-"+ext
	return os.path.join(get_servers_config_dir(), "%s@%s:%s.%s" % (server.username, server.host, server.port, ext))



def modify_object_properties(filename, instance, fields_to_save):
	reloaded = load_object_from_properties(filename, instance.__class__)
	mods = []
	for field in fields_to_save:
		old_value = getattr(reloaded, field)
		new_value = getattr(instance, field)
		if old_value!=new_value:
			mods.append((old_value, new_value))
			setattr(reloaded, field, new_value)
		logger.sdebug("reloaded=%s, old_value=%s, new_value=%s" % (reloaded, old_value, new_value), filename, instance, csv_list(fields_to_save))
	logger.sdebug("reloaded=%s, changes=%s" % (reloaded, csv_list(mods)), filename, instance, csv_list(fields_to_save))
	if len(mods)>0:
		save_object_to_properties(filename, reloaded)

#
# load/save a class to a properties file (see PERSIST)
#
def load_object_from_properties(filename, instance_type, keys_in=None, extra_keys=None, constructor=None, newerversion_constructor=None, ignored_keys=[], warn_on_missing_keys=True, warn_on_extra_keys=True, resave_newerversion=True):
	props = load_properties(filename)
	if not props:
		return	None
	saved_version = props.get(VERSION_KEY)
	if saved_version:
		saved_version = saved_version.replace('"', '').replace("'", "")
	is_new_version = False
	if not saved_version or saved_version!=WINSWITCH_VERSION:
		if warn_on_missing_keys:
			logger.sdebug("different version: file is from %s, current version is %s" % (saved_version, WINSWITCH_VERSION), filename, instance_type, keys_in, extra_keys, constructor, newerversion_constructor, ignored_keys, warn_on_missing_keys, warn_on_extra_keys)
		is_new_version = True
	try:
		if is_new_version and newerversion_constructor:
			instance = newerversion_constructor()
		elif constructor:
			instance = constructor()
		else:
			instance = instance_type()
	except Exception, e:
		logger.serr("failed to instantiate!", e, )
		raise e
	populate_object_from_properties(props, instance, instance_type, keys_in, extra_keys, ignored_keys, warn_on_missing_keys, warn_on_extra_keys)
	#set the filename used on the object:
	set_object_stored_as_filename(instance, filename)
	if is_new_version and newerversion_constructor and resave_newerversion:
		save_object_to_properties(filename, instance)			#save the newer version
	return	instance

def populate_object_from_properties(props, instance, instance_type, keys_in=None, extra_keys=None, ignored_keys=[], warn_on_missing_keys=True, warn_on_extra_keys=True):
	"""
	Populates an object from a properties file.
	props: the properties to set
	instance: the object being populated
	instance_type: used to find the keys to populate
	keys_in: the list of fields to load (overrides the list we would obtain from the instance_type).
	extra_keys: extra fields we will load (for loading fields not normally persisted).
	"""
	sig = msig("{..}", instance, instance_type, csv_list(keys_in), csv_list(extra_keys), csv_list(ignored_keys), warn_on_missing_keys, warn_on_extra_keys)
	logger.debug(sig)
	keys=keys_in
	if not keys:
		keys = get_persist(instance_type)
		if not keys:
			raise Exception("cannot find keys to load for %s!" % instance_type)
	if extra_keys and len(extra_keys)>0:
		for key in extra_keys:
			if key not in keys:
				keys.append(key)

	for key in keys:
		if key.startswith("#") or key in ignored_keys:
			continue
		raw_value = props.get(key)
		value = raw_value
		if key in props:
			del props[key]		#used it: remove from list
		try:
			current_value = getattr(instance,key)
			value_type = type(current_value)
		except AttributeError, e:
			logger.error(sig+" invalid key '%s': %s" % (key, e))
			continue
		try:
			if raw_value == "None":
				value = None
			if raw_value != "None" and not value and (value_type not in [types.ListType, types.DictType]):
				if warn_on_missing_keys:
					logger.error(sig+" '%s' is missing! (type=%s) keeping current value: %s" % (key, value_type, current_value))
				continue

			keys_used = []
			if value_type is types.StringType or value_type is types.UnicodeType:
				value = unquote(value)
			elif value_type is types.BooleanType:
				value = get_bool(value)
			elif value_type is types.FloatType:
				value = float(value)
			elif value_type is types.IntType:
				value = int(value)
			elif value_type is types.LongType:
				value = long(value)
			elif value_type is types.DictType:
				if value=="" or value=="{}":	#used for detecting an empty dict
					value = {}
					setattr(instance, key, value)
					continue
				re_exp = "^%s\[\"(.*)\"\]$" % key
				kv_re = re.compile(re_exp)
				value = {}
				for tk,tv in props.items():
					match = kv_re.match(tk)
					if not match:
						continue
					dict_key = match.group(1)
					keys_used.append(tk)
					value[dict_key] = unquote(tv)
			elif value_type is types.ListType:
				if value=="" or value=="[]":	#used for detecting empty array
					value = []
					setattr(instance, key, value)
					continue
				re_exp = "^%s\[(\d*)\]$" % key
				el_re = re.compile(re_exp)
				keys_used = []
				list_values = {}
				for tk,tv in props.items():
					match = el_re.match(tk)
					if not match:
						continue
					index_str = match.group(1)
					try:
						index = int(index_str)
						keys_used.append(tk)
						list_values[index] = unquote(tv)
					except:
						logger.error(sig+" failed to parse array %s index: %s" % (key, index_str))
						continue
				list_values.keys().sort()
				value = list_values.values()
				if len(value)==0:
					if warn_on_missing_keys:
						logger.error(sig+" array '%s' is missing!" % key)
					continue
			else:
				logger.error(sig+" illegal type: %s for field %s" % (str(value_type),key))
				continue
			#remove keys used:
			for key_used in keys_used:
				del props[key_used]
			setattr(instance, key, value)
		except Exception, e:
			logger.error(sig+" error on key %s with value=%s" % (key,value), e)
	#check for invalid keys:
	if VERSION_KEY in props:
		del props[VERSION_KEY]
	if warn_on_extra_keys and len(props)>0:
		logger.error(sig+" found some unused/invalid keys: %s" % props)


def set_object_stored_as_filename(instance, filename):
	setattr(instance, "stored_as_filename", filename)

def get_object_stored_as_filename(instance):
	return getattr(instance, "stored_as_filename", None)

def save_object_to_properties(filename, instance, keys=None, chmod=None):
	logger.sdebug(filename,instance,keys,chmod)
	props = get_persist_dict(instance, keys)
	props[VERSION_KEY] = WINSWITCH_VERSION
	if keys is None:
		keys = get_persist(instance)
	if VERSION_KEY not in keys:
		keys.insert(0, VERSION_KEY)
	save_properties(filename, props, key_order=keys)
	if chmod:
		os.chmod(filename, chmod)
	set_object_stored_as_filename(instance, filename)

def load_properties(filename, clobber=True):
	if not is_valid_file(filename):
		logger.sdebug("is not a valid file!", filename)
		return None
	propFile = open(filename, "rU")
	propDict = dict()
	for propLine in propFile:
		propDef= propLine.strip()
		if len(propDef) == 0:
			continue
		if propDef[0] in ( '!', '#' ):
			continue
		punctuation = [ propDef.find(c) for c in ':= ' ] + [ len(propDef) ]
		found = min( [ pos for pos in punctuation if pos != -1 ] )
		name= propDef[:found].rstrip()
		value= propDef[found:].lstrip(":= ").rstrip()
		if clobber or (name not in propDict):
			propDict[name]= value
	propFile.close()
	return propDict


def save_properties(filename, props,
				header="# %s Configuration File\n\n\n" % APPLICATION_NAME,
				quote="\"",
				key_order=None):
	propFile = open(filename, "w")
	if header:
		propFile.write("%s\n" % header)
	if not key_order:
		key_order = props.keys()
	for key in key_order:
		if key.startswith("#"):
			propFile.write("%s\n" % key)			#comments
			continue

		assert key in props.keys()
		value = props.get(key)
		value_type = type(value)
		if value_type is types.StringType or value_type is types.UnicodeType:
			value = '%s%s%s' % (quote, value, quote)
		elif value_type is types.DictType:
			if not value or len(value)==0:
				propFile.write("%s={}\n" % key)		#empty dict marker
			else:
				for k,v in value.items():
					propFile.write("%s[\"%s\"]=%s\n" % (key, k, v))
			continue
		elif value_type is types.ListType:
			if len(value)==0:
				propFile.write("%s=[]\n" % key)		#empty array marker
				continue
			index = 0
			for element in value:
				propFile.write("%s[%d]=\"%s\"\n" % (key, index, element))
				index += 1
			continue
		elif value_type not in [types.BooleanType, types.FloatType, types.IntType, types.LongType, types.NoneType]:
			logger.serr("illegal type: %s for field %s" % (value_type,key), None, filename, "{..}", header)
			continue
		propFile.write("%s=%s\n" % (key, value))
	propFile.close()


def get_persist_dict(obj, keys_in=None):
	keys = keys_in
	if not keys_in:
		keys = get_persist(obj.__class__)
	if not keys:
		return obj.__dict__
	d = {}
	for key in keys:
		if key.startswith("#"):
			continue
		d[key] = getattr(obj, key)
	return d

def get_persist(object_type):
	if not hasattr(object_type, 'PERSIST'):
		return	None
	persist = getattr(object_type, "PERSIST")
	if persist is None:
		return	persist
	return persist[:]





def load_GPL3():
	paths = [APP_DIR]
	if WINSWITCH_SHARE_DIR!=APP_DIR:
		paths.append(WINSWITCH_SHARE_DIR)
	filename = None
	try:
		for path in paths:
			filename = os.path.join(path, "COPYING")
			gpl3 = load_binary_file(filename)
			if gpl3:
				return	gpl3
	except:
		logger.serr("error reading from '%s'" % filename)
		gpl3 = None
	if not gpl3:
		gpl3 = "Your installation may be corrupted, the license text for GPL version 3 could not be found,\nplease refer to:\nhttp://www.gnu.org/licenses/gpl-3.0.txt"
	return gpl3
