#!/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 sys
import os.path

from winswitch.objects.server_base import ServerBase
from winswitch.objects.server_command import ServerCommand
from winswitch.objects.session import ALLOW_SSH_DESKTOP_MODE
from winswitch.util.paths import HOST_PUBLIC_KEY_FILE, DEVILSPIE_VNC_CONFIG, DESKTOP_BACKGROUND, WINSWITCH_SHARE_DIR, APP_DIR, WINSWITCH_LIBEXEC_DIR, ETC_SEARCH_ORDER
from winswitch.util.common import is_valid_file, is_valid_exe, get_xpra_version, do_check_xpra_version_string, get_platform_detail, get_os_version, has_unix_group, CAN_USE_GIO, load_binary_file, is_valid_dir, generate_UUID, is_xpra_version_ok
from winswitch.consts import DEFAULT_FIXED_SERVER_PORT, XVNC_TIGER, XVNC_TIGHT, DEFAULT_IGNORED_COMMANDS, DEFAULT_IGNORED_XSESSIONS, DEFAULT_RDP_PORT, BINASCII, BASE64, REQUIRED_XPRASHADOW_MIN_VERSION
from winswitch.globals import WIN32, OSX
from winswitch.util.gstreamer_util import get_default_gst_sound_sink_module, get_default_gst_sound_sink_options, get_default_gst_sound_source_module, \
					get_default_gst_sound_source_options, get_default_gst_video_source_module, has_tcp_plugins, AUTO_SINK, AUTO_SOURCE, \
					supported_gstaudio_codecs, supported_gstvideo_codecs
from winswitch.util.commands_util import XPRA_COMMAND, XVNC_COMMAND, XNEST_COMMAND, WINVNC_COMMAND, \
	VNCSHADOW_COMMAND, NXAGENT_COMMAND, VNCCONFIG_COMMAND, VNCPASSWD_COMMAND, \
	PULSEAUDIO_COMMAND, DEVILSPIE_COMMAND, XLOADIMAGE_COMMAND, XSET_COMMAND, SCREEN_COMMAND, VIRSH_COMMAND, VBOXMANAGE_COMMAND, VBOXHEADLESS_COMMAND, \
	XWD_COMMAND, PNMTOPNG_COMMAND, XWDTOPNM_COMMAND, IMPORT_COMMAND, CUPSD_COMMAND, GNOME_KEYRING_DAEMON_COMMAND, \
	get_xvnc_type
from winswitch.util.process_util import get_output

from winswitch.util.simple_logger import Logger
logger=Logger("server_settings", log_colour=Logger.CYAN)

DEFAULT_UTMP_DETECT_BATCH_DELAY = 800		#delay in milliseconds for batching detect requests


def detect_default_locale():
	if WIN32 or OSX:
		return	""
	try:
		cmd = ["locale"]
		code, out, _ = get_output(cmd)
		if code==0:
			for x in out.splitlines():
				if x.startswith("LANG="):
					return	x[len("LANG="):].strip()
	except:
		pass
	return	""

def detect_locales():
	if WIN32 or OSX:
		return	[]
	import locale
	logger.sdebug("sys.getdefaultencoding()=%s, sys.stdout.encoding=%s" % (sys.getdefaultencoding(), sys.stdout.encoding))
	logger.sdebug("locale.getpreferredencoding()=%s" % (locale.getpreferredencoding()))
	try:
		#first try with "-v" and decode the names with the codeset specified
		cmd = ["locale", "-a", "-v"]
		code, out, _ = get_output(cmd)
		if code==0:
			locales = []
			def add_locale(loc, codeset):
				if loc is not None:
					#add current record
					if codeset:
						try:
							d = loc.decode(codeset).encode("utf-8")
							#logger.sdebug("%s.decode(%s).encode('utf-8')=%s (%s)" % (loc, codeset, d, type(d)))
							#if loc.startswith("fr"):
							#	logger.sdebug("%s=%s" % (loc, [x for x in d]))
							locales.append(d)
						except Exception, e:
							logger.slog("%s.decode(%s) failed: %s" % (loc, codeset, e))
							locales.append(loc)
					else:
						locales.append(loc)
			loc = None
			codeset = None
			for line in out.splitlines():
				if line.startswith("locale:"):
					add_locale(loc, codeset)
					loc = None
					codeset = None
					#ie: locale: aa_DJ.iso88591  archive: /usr/lib/locale/locale-archive
					p = line.split(" ")
					if len(p)>=2:
						loc = p[1]		#ie: aa_DJ.iso88591
				elif line.find("codeset")>=0:
					p = line.split("|")
					if len(p)==2:
						codeset = p[1].strip()
			add_locale(loc, codeset)
			if len(locales)>0:
				return	locales
	except:
		pass
	try:
		cmd = ["locale", "-a"]
		code, out, _ = get_output(cmd)
		if code==0:
			return	out.splitlines()
	except:
		pass
	return	[]

def get_default_VNC_commands():
	commands = []
	# devilspie to maximize windows
	config = os.path.join(WINSWITCH_SHARE_DIR, DEVILSPIE_VNC_CONFIG)
	if is_valid_exe(DEVILSPIE_COMMAND) and is_valid_file(config):
		commands.append("%s %s" % (DEVILSPIE_COMMAND, config))
	# set a background
	bg = os.path.join(WINSWITCH_SHARE_DIR, DESKTOP_BACKGROUND)
	if is_valid_exe(XLOADIMAGE_COMMAND) and is_valid_file(bg):
		commands.append("%s -fullscreen -onroot %s" % (XLOADIMAGE_COMMAND, bg))
	# use vncconfig to share clipboard
	if is_valid_exe(VNCCONFIG_COMMAND):
		commands.append("%s -nowin" % VNCCONFIG_COMMAND)
	return	commands

def get_default_desktop_commands():
	commands = []
	#disable screensaver
	if is_valid_exe(XSET_COMMAND):
		commands.append("%s s off" % XSET_COMMAND)
	return	commands

def get_default_window_manager_command():
	if WIN32:
		return	""
	WINDOW_MANAGERS = ["sawfish", "metacity", "emerald",
					"gtk-window-decorator",
					"blackbox", "fluxbox", "openbox", "matchbox", "fvwm", "icewm",
					"twm"]
	WM_ARGS = {"metacity" : "--no-composite"}
	from winswitch.util.which import which
	for wm in WINDOW_MANAGERS:
		c = which(wm)
		if not is_valid_exe(c):
			continue
		if wm not in WM_ARGS:
			return	c
		return "%s %s" % (c, WM_ARGS.get(wm))
	return	""

def get_screen_capture_command():
	""" Returns the command that can be used to take screnshots of the current display
		The filename to save to will be appended to this command.
	"""
	if OSX:
		return	"screencapture -x -tpng "
	if is_valid_exe(IMPORT_COMMAND):
		return "%s -screen -silent -window root -compress JPEG jpeg:" % IMPORT_COMMAND
	if is_valid_exe(XWD_COMMAND) and is_valid_exe(XWDTOPNM_COMMAND) and is_valid_exe(PNMTOPNG_COMMAND):
		return "%s -root -silent | %s | %s > " % (XWD_COMMAND, XWDTOPNM_COMMAND, PNMTOPNG_COMMAND)
	return	""


def get_ssh_config_dir_search_order():
	return	["%s/ssh" % ETC_SEARCH_ORDER]+ETC_SEARCH_ORDER

def get_default_ssh_host_public_key_file():
	if not WIN32:
		dirs = get_ssh_config_dir_search_order()
		for d in dirs:
			if is_valid_dir(d):
				filename = os.path.join(d, HOST_PUBLIC_KEY_FILE)
				if is_valid_file(filename):
					return filename
	return	""




class ServerSettings(ServerBase):
	"""
	These are the settings used by a WindowSwitchServer instance.
	"""

	PERSIST = ServerBase.PERSIST_COMMON + [
			"# The server's private key:",
			"crypto_private_exponent", "key_fingerprint",
			"# Will the local display be exported to remote clients:",
			"export_local_displays",
			"# Address(es) for the server socket to listen on (ie: eth0:12321, *:12321, eth1:, lo:,):",
			"listen_on",
			"# You should not allow root logins unless you know what you are doing!",
			"allow_root_logins",
			"# Root authentication allows you to login as another user without knowing their password",
			"allow_root_authentication",
			"# Close sessions when server stops (the server is normally able to reload them on re-start):",
			"close_sessions_on_exit",
			"# Cleanup session directory when session terminates:",
			"delete_session_files",
			"# mDNS settings:",
			"mDNS_publish", "mDNS_publish_username",
			"# Debugging options:",
			"debug_mode",
			"# For integrating with a firewall via scripts:",
			"firewall_script", "firewall_enabled",
			"# The maximum connection speed from this server to remote clients:",
			"max_line_speed",
			"# Which authentication module to use (only PAM is supported for now):",
			"authentication_module",
			"# Grant SSH access to users who have authenticated: (adds their ssh public key to SSH authorized_keys)",
			"grant_ssh_access",
			"# Warning: if set and non-empty, this password can be used to login - bypassing any system password set!",
			"magic_password_bypass",
			"# List of commands/x-sessions which will be ignored when loaded from the .desktop menu files:",
			"ignored_commands",
			"ignored_xsessions",
			"# Whitelist of commands: commands must match these to be enabled:",
			"whitelist_commands",
			"whitelist_xsessions",
			"# Can the clients start custom commands not found in .desktop files:",
			"allow_custom_commands",
			"# Can the clients send files to open:",
			"allow_file_transfers",
			"# Where to store the files uploaded:",
			"download_directory",
			"# Path to some commands:",
			"screen_command",
			"pulseaudio_command",
			"vboxheadless_command",
			"vboxmanage_command",
			"xpra_command",
			"# Do we want to start the gnome keyrind daemon:",
			"start_gnome_keyring_daemon", "gnome_keyring_daemon_command",
			"# Does the server support SSH X11 display forwarding?:",
			"supports_ssh",
			"# Can clients mount remote filesystems and where?",
			"mount_client", "mount_location",
			"# to turn off sound completely:",
			"supports_sound",
			"# gstreamer sound configuration for receiving/exporting sound from/to the local display:",
			"gst_sound_sink_module", "gst_sound_sink_options", "gst_sound_source_module", "gst_sound_source_options",
			"# gstreamer video configuration:",
			"# known options: autovideosrc (all), ximagesrc (*nix)",
			"gstvideo_src_plugin",
			]
	if OSX:	#only meaningful on OSX:
		PERSIST.append("application_directory")

	if WIN32:			#only used on win32:
		PERSIST += ["winvnc_command", "supports_winvnc", "winvnc_port", "show_vnc_tray",
				"rdp_seamless_command"]
	else:
		#non-win32 options:
		PERSIST += [
			"ssh_host_public_key_file",
			"# allow clients to stop the server remotely:",
			"clients_can_stop",
			"# Xnest is used for simulating desktop mode with xpra and ssh:",
			"xnest_command",
			"# SMB commands used for mounting and unmounting:",
			"smbmount_command", "smbumount_command",
			"# to capture screenshots:",
			"screen_capture_command",
			"# delay for utmp batch parsing (in milliseconds), set to a negative value to let the system auto-tune itself:",
			"utmp_batch_delay"
			]
	if not OSX and not WIN32:
		#these can't be used on osx or win32 - so no need to save them:
		PERSIST += [
			"# command to use for opening files sent by the clients:",
			"default_open_command",
			"# pre-launch some sessions:",
			"prelaunch_users", "prelaunch_enabled",
			"# commands to start automatically with desktop sessions:",
			"desktop_session_commands",
			"desktop_window_manager_command",
			"dbus_command",
			"# NX:",
			"nxagent_command",
			"# libvirt support:",
			"virsh_command", "libvirt_uris",
			"# locales supported (see `locale -a`)",
			"locales", "default_locale",
			"# vnc support:",
			"xvnc_command", "xvnc_options", "vnc_session_commands", "vncshadow_command", "vncpasswd_command"
			]
	PERSIST += [
			"# How often to run screen capture in seconds (use 0 or a negative value to disable it):",
			"screen_capture_delay"
			]


	def __init__(self, skip_detection=False):
		self.debug_mode = False
		if WIN32:
			#use a fixed port on win32
			self.listen_on = "*:%s" % DEFAULT_FIXED_SERVER_PORT
		else:
			self.listen_on = "*:"
		self.delete_session_files = True				#remove each session's directory on exit
		self.allow_root_logins = False					#use sudo instead
		self.allow_root_authentication = True			#authenticate as another user via root/Administrator
		self.mDNS_publish = True						#publish via mDNS
		self.mDNS_publish_username = True				#include the username this is for?
		self.firewall_enabled = False					#call the firewall script?
		if WINSWITCH_LIBEXEC_DIR:
			self.firewall_script = os.path.join(WINSWITCH_LIBEXEC_DIR, "firewall")
		else:
			self.firewall_script = None
		self.max_line_speed = 10*1000*1000				#maximum connection speed possible on this server
		self.authentication_module = "PAM"				#PAM is default auth module
		#self.authentication_module = "KRB5"			#Kerberos as fallback...
		self.magic_password_bypass = ""					#A magic password that can be used to authenticate without using PAM/KRB5
		self.grant_ssh_access = True					#user's ssh keys will be added to SSH's authorized_keys
		if skip_detection:
			self.ssh_host_public_key_file = ""
		else:
			self.ssh_host_public_key_file = get_default_ssh_host_public_key_file()
		self.export_local_displays =  True
		self.close_sessions_on_exit = False				#may be useful when debugging
		self.prelaunch_enabled = CAN_USE_GIO			#without gio, we would eat up too much CPU polling preloaded session files
		self.prelaunch_users = []
		self.local_session_owner = ""					#the uuid of the local user

		self.dbus_command = "dbus-daemon --fork --print-address=1 --print-pid=1 --session"

		self.nxagent_command = NXAGENT_COMMAND
		self.pulseaudio_command = PULSEAUDIO_COMMAND
		self.xpra_command = XPRA_COMMAND
		self.xnest_command = XNEST_COMMAND
		self.xvnc_command = XVNC_COMMAND
		self.vncshadow_command = VNCSHADOW_COMMAND
		self.vncpasswd_command = VNCPASSWD_COMMAND
		self.show_vnc_tray = False
		self.screen_command = SCREEN_COMMAND
		self.vboxheadless_command = VBOXHEADLESS_COMMAND
		self.vboxmanage_command = VBOXMANAGE_COMMAND
		self.gnome_keyring_daemon_command = GNOME_KEYRING_DAEMON_COMMAND
		self.start_gnome_keyring_daemon = is_valid_exe(GNOME_KEYRING_DAEMON_COMMAND)
		if WINSWITCH_LIBEXEC_DIR:
			self.default_open_command = os.path.join(WINSWITCH_LIBEXEC_DIR, "mime_open")
		else:
			self.default_open_command = None
		self.virsh_command = VIRSH_COMMAND
		self.libvirt_uris = ["qemu:///session", "uml:///session"]
		self.winvnc_command = WINVNC_COMMAND
		self.supports_winvnc = skip_detection or is_valid_exe(WINVNC_COMMAND)
		self.rdp_version = ""
		if skip_detection:
			self.xvnc_options = []
			self.vnc_session_commands = []
			self.desktop_session_commands = []
			self.desktop_window_manager_command = ""
			self.screen_capture_command = ""
		else:
			self.xvnc_options = self.get_default_xvnc_options(self.xvnc_command)
			self.vnc_session_commands = get_default_VNC_commands()
			self.desktop_session_commands = get_default_desktop_commands()
			self.desktop_window_manager_command = get_default_window_manager_command()
			self.screen_capture_command = get_screen_capture_command()
		self.screen_capture_delay = 30
		#Video:
		self.gstvideo_src_plugin = get_default_gst_video_source_module()
		#Sound: only used on win32, on other platforms each session has its own pulse server:
		if skip_detection or WIN32:
			self.gst_sound_sink_module = AUTO_SINK
			self.gst_sound_sink_options = {}
			self.gst_sound_source_module = AUTO_SOURCE
			self.gst_sound_source_options = {}
		else:
			self.gst_sound_sink_module = get_default_gst_sound_sink_module()
			self.gst_sound_sink_options = get_default_gst_sound_sink_options(self.gst_sound_sink_module)
			self.gst_sound_source_module = get_default_gst_sound_source_module()
			self.gst_sound_source_options = get_default_gst_sound_source_options(self.gst_sound_source_module)
		self.ignored_commands = DEFAULT_IGNORED_COMMANDS
		self.whitelist_commands = ["*"]
		self.ignored_xsessions = DEFAULT_IGNORED_XSESSIONS
		self.whitelist_xsessions = ["*"]
		self.mount_location = "~/Desktop"
		self.mount_client = True
		self.smbmount_command = "sudo -n mount -t cifs"
		self.smbumount_command = "sudo -n umount"
		#detected:
		self.xpra_version = ""
		self.xpra_version_checked = False
		#do superclass init last as it will rely on some of the vars above (via test_support_xxxx)
		self.is_new = False
		self.firewall_test_failed = None			#used during the initial firewall test
		""" Superclass initialisation """
		ServerBase.__init__(self, skip_detection)

		self.binary_encodings = [BINASCII, BASE64]
		self.gstaudio_codecs = supported_gstaudio_codecs
		self.gstvideo_codecs = supported_gstvideo_codecs
		if WIN32:
			from winswitch.virt.rdp_common_util import get_RDP_Port, get_RDP_ProductVersion
			self.rdp_port = get_RDP_Port() or DEFAULT_RDP_PORT
			self.rdp_version = get_RDP_ProductVersion() or ""
			self.allow_file_transfers = False		#we can't open seamless sessions, so no point in doing file uploads
		self.ssh_tunnel = False						#ssh tunnel off by default (controller.py will try to detect it)
		self.platform = get_platform_detail()
		self.os_version = get_os_version()
		self.application_directory = APP_DIR			#used on OSX to detect location change
		self.cupsd_command = CUPSD_COMMAND
		if not is_valid_exe(self.cupsd_command):
			self.cupsd_command = ""
			self.tunnel_printer = False
		self.utmp_batch_delay = -1		#on *nix, how long we wait before parsing utmp after changes
		if not skip_detection:
			self.default_locale = detect_default_locale()
			self.locales = detect_locales()


	def detect_xpra_encodings(self):
		try:
			all_encodings = []
			from xpra.codecs.loader import has_codec
			for codec_name, encodings in {
						"enc_vpx" 	: ["vpx"],
						"enc_x264"	: ["x264"],
					  	"enc_webp"  : ["webp"],
						"PIL"	    : ["png", "png/L", "png/P", "jpeg"],
						}.items():
				if has_codec(codec_name):
					all_encodings += encodings
			logger.slog("=%s" % str(all_encodings))
			return all_encodings
		except:
			pass
		#older versions:
		try:
			from xpra.scripts.config import ENCODINGS			#@UnresolvedImport
			return	ENCODINGS
		except:
			pass
		#even older:
		try:
			from xpra.scripts.main import ENCODINGS			#@UnresolvedImport @Reimport
			return	ENCODINGS
		except:
			pass
		return	[]

	def test_supports_fileopen(self):
		return	not WIN32			#we cant server individual apps on win32

	def test_supports_xpra_desktop(self):
		return	is_valid_exe(self.xnest_command)

	def test_supports_xpra(self):
		""" xpra requires the xpra_command and xvfb_command, does not work on win32 (and never will natively) or OSX (not yet?) """
		return	not OSX and not WIN32 and is_valid_exe(self.xpra_command)

	def test_supports_xprashadow(self):
		if not self.test_supports_xpra():
			return	False
		self.detect_xpra_version()
		if not self.xpra_version:
			return	False
		return is_xpra_version_ok(self.xpra_version, min_version=REQUIRED_XPRASHADOW_MIN_VERSION)

	def test_supports_nx(self):
		""" NX does not word on windows or osx: """
		return	not OSX and not WIN32 and is_valid_exe(self.nxagent_command)

	def test_supports_vnc(self):
		return	is_valid_exe(self.xvnc_command)

	def test_supports_vncshadow(self):
		if OSX:
			return	has_unix_group("admin")						#we need admin to be able to enable/control the vnc server
		elif WIN32:
			return	is_valid_file(self.winvnc_command)
		else:
			return	is_valid_exe(self.vncshadow_command)

	def test_supports_gstvideo(self):
		return	has_tcp_plugins and get_default_gst_video_source_module() is not None

	def test_supports_rdp(self):
		if not WIN32:
			return	False
		from winswitch.virt.rdp_common_util import supports_rdp
		return supports_rdp()

	def test_supports_rdp_seamless(self):
		rdp_s = is_valid_file(self.rdp_seamless_command)
		self.slog("=%s" % rdp_s)
		return rdp_s

	def test_supports_ssh(self):
		if sys.platform.startswith("win"):
			return	False
		from winswitch.util.which import which_extra
		sshd = which_extra(["/usr/sbin", "/usr/local/sbin"], "sshd")
		code = -1
		sshd_config = ""
		if not is_valid_file(sshd):
			self.serror("cannot find sshd, assuming that ssh is not installed and X11 forwarding cannot work")
			return	False
		cmd = [sshd, "-T"]
		try:
			code, sshd_config, _ = get_output(cmd)
		except Exception, e:
			self.serr("failed to run '%s'" % cmd, e)
			code = -1
		if code!=0 or (sshd_config and sshd_config.endswith("Permission denied")):
			self.serror("cannot run 'sshd -T' to verify: '%s', assuming X11 Forwarding is enabled!" % sshd_config)
			return	True
		if not sshd_config:
			config_options = [("%s/sshd_config" % x) for x in get_ssh_config_dir_search_order()]
			for config_file in config_options:
				sshd_config = load_binary_file(config_file)
				if sshd_config:
					break
		if not sshd_config:
			self.serror("cannot find sshd_config file, assuming that x11forwarding will not work!")
			return	False
		import re
		allowed_re = re.compile("x11forwarding\s*yes")
		notallowed_re = re.compile("x11forwarding\s*no")
		default_value = None
		found_value = None
		for line in sshd_config.lower().splitlines():
			commented_out = line.startswith("#")
			if commented_out:
				line = line[1:]
			if allowed_re.match(line.strip()):
				if commented_out:
					self.slog("OK: X11 Forwarding is enabled by default? (config line=#%s)" % line)
					default_value = True
				else:
					self.slog("OK: X11 Forwarding is enabled (config line=%s)" % line)
					found_value = True
			if notallowed_re.match(line.strip()):
				if commented_out:
					self.slog("Error: X11 Forwarding is NOT enabled by default? (config line=#%s)" % line)
					default_value = False
				else:
					self.serror("Error: X11 Forwarding is NOT enabled (config line=%s)" % line)
					found_value = False
		if found_value:
			return	found_value
		if default_value is None:
			#it seems to be on by default on freebsd:
			default_value = sys.platform.startswith("freebsd")
		self.serror("X11 Forwarding was not specified explicitly - assuming x11forwarding=%s" % default_value)
		return	default_value

	def test_supports_ssh_desktop(self):
		return	ALLOW_SSH_DESKTOP_MODE and is_valid_exe(self.xnest_command)

	def test_supports_screen(self):
		return	is_valid_exe(self.screen_command)

	def test_supports_libvirt(self):
		try:
			import libvirt			#@UnresolvedImport
			assert libvirt
			return	is_valid_exe(self.virsh_command)
		except:
			return	False

	def test_supports_virtualbox(self):
		return is_valid_exe(self.vboxmanage_command) and is_valid_exe(self.vboxheadless_command)


	def get_default_xvnc_options(self, xvnc_command):
		"""
		Depending on the type of the Xvnc server, we can supply different customizations..
		"""
		xvnc_type = get_xvnc_type(xvnc_command)
		if xvnc_type == XVNC_TIGER:
			return ["+extension", "RANDR", "-br"]
		elif xvnc_type == XVNC_TIGHT:
			return	[]		#could add options specific to TightVNC here
		return []

	def detect_default_locale(self):
		if WIN32 or OSX:
			return	""
		try:
			cmd = ["locale"]
			code, out, _ = get_output(cmd)
			if code==0:
				for x in out.splitlines():
					if x.startswith("LANG="):
						return	x[len("LANG="):].strip()
		except:
			pass
		return	""

	def detect_locales(self):
		if WIN32 or OSX:
			return	[]
		try:
			cmd = ["locale", "-a"]
			code, out, _ = get_output(cmd)
			if code==0:
				return	out.splitlines()
		except:
			pass
		return	[]

	def get_new_prelaunch_command_object(self):
		PRELAUNCH_SESSION_NAME = "pre-launch"
		sc = ServerCommand(generate_UUID(), PRELAUNCH_SESSION_NAME,
							"delayed_start",	#placeholder, not actually used as-is
							"nc", None)
		return	sc

	def detect_xpra_version(self):
		if not self.xpra_version:
			self.xpra_version = get_xpra_version(self.xpra_command)
			self.xpra_version_checked = do_check_xpra_version_string(self.xpra_version)

	def __str__(self):
		return	"ServerSettings(%s)" % self.name
