--- /dev/null
+/* Copyright (C) 2016 Brian P. Hinz
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+package com.tigervnc.vncviewer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.PrintWriter;
+import java.util.StringTokenizer;
+
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Exception;
+
+public class Parameters {
+
+
+ public static BoolParameter noLionFS
+ = new BoolParameter("NoLionFS",
+ "On Mac systems, setting this parameter will force the use of the old "+
+ "(pre-Lion) full-screen mode, even if the viewer is running on OS X 10.7 "+
+ "Lion or later.",
+ false);
+
+ public static BoolParameter embed
+ = new BoolParameter("Embed",
+ "If the viewer is being run as an applet, display its output to " +
+ "an embedded frame in the browser window rather than to a dedicated " +
+ "window. Embed=1 implies FullScreen=0 and Scale=100.",
+ false);
+
+ public static BoolParameter useLocalCursor
+ = new BoolParameter("UseLocalCursor",
+ "Render the mouse cursor locally",
+ true);
+
+ public static BoolParameter sendLocalUsername
+ = new BoolParameter("SendLocalUsername",
+ "Send the local username for SecurityTypes "+
+ "such as Plain rather than prompting",
+ true);
+
+ public static StringParameter passwordFile
+ = new StringParameter("PasswordFile",
+ "Password file for VNC authentication",
+ "");
+
+ public static AliasParameter passwd
+ = new AliasParameter("passwd",
+ "Alias for PasswordFile",
+ passwordFile);
+
+ public static BoolParameter autoSelect
+ = new BoolParameter("AutoSelect",
+ "Auto select pixel format and encoding",
+ true);
+
+ public static BoolParameter fullColor
+ = new BoolParameter("FullColor",
+ "Use full color - otherwise 6-bit colour is "+
+ "used until AutoSelect decides the link is "+
+ "fast enough",
+ true);
+
+ public static AliasParameter fullColorAlias
+ = new AliasParameter("FullColour",
+ "Alias for FullColor",
+ Parameters.fullColor);
+
+ public static IntParameter lowColorLevel
+ = new IntParameter("LowColorLevel",
+ "Color level to use on slow connections. "+
+ "0 = Very Low (8 colors), 1 = Low (64 colors), "+
+ "2 = Medium (256 colors)",
+ 2);
+
+ public static AliasParameter lowColorLevelAlias
+ = new AliasParameter("LowColourLevel",
+ "Alias for LowColorLevel",
+ lowColorLevel);
+
+ public static StringParameter preferredEncoding
+ = new StringParameter("PreferredEncoding",
+ "Preferred encoding to use (Tight, ZRLE, "+
+ "hextile or raw) - implies AutoSelect=0",
+ "Tight");
+
+ public static BoolParameter viewOnly
+ = new BoolParameter("ViewOnly",
+ "Don't send any mouse or keyboard events to "+
+ "the server",
+ false);
+
+ public static BoolParameter shared
+ = new BoolParameter("Shared",
+ "Don't disconnect other viewers upon "+
+ "connection - share the desktop instead",
+ false);
+
+ public static BoolParameter fullScreen
+ = new BoolParameter("FullScreen",
+ "Full Screen Mode",
+ false);
+
+ public static BoolParameter fullScreenAllMonitors
+ = new BoolParameter("FullScreenAllMonitors",
+ "Enable full screen over all monitors",
+ true);
+
+ public static BoolParameter acceptClipboard
+ = new BoolParameter("AcceptClipboard",
+ "Accept clipboard changes from the server",
+ true);
+
+ public static BoolParameter sendClipboard
+ = new BoolParameter("SendClipboard",
+ "Send clipboard changes to the server",
+ true);
+
+ public static IntParameter maxCutText
+ = new IntParameter("MaxCutText",
+ "Maximum permitted length of an outgoing clipboard update",
+ 262144);
+
+ public static StringParameter menuKey
+ = new StringParameter("MenuKey",
+ "The key which brings up the popup menu",
+ "F8");
+
+ public static StringParameter desktopSize
+ = new StringParameter("DesktopSize",
+ "Reconfigure desktop size on the server on "+
+ "connect (if possible)", "");
+
+ public static BoolParameter listenMode
+ = new BoolParameter("listen",
+ "Listen for connections from VNC servers",
+ false);
+
+ public static StringParameter scalingFactor
+ = new StringParameter("ScalingFactor",
+ "Reduce or enlarge the remote desktop image. "+
+ "The value is interpreted as a scaling factor "+
+ "in percent. If the parameter is set to "+
+ "\"Auto\", then automatic scaling is "+
+ "performed. Auto-scaling tries to choose a "+
+ "scaling factor in such a way that the whole "+
+ "remote desktop will fit on the local screen. "+
+ "If the parameter is set to \"FixedRatio\", "+
+ "then automatic scaling is performed, but the "+
+ "original aspect ratio is preserved.",
+ "100");
+
+ public static BoolParameter alwaysShowServerDialog
+ = new BoolParameter("AlwaysShowServerDialog",
+ "Always show the server dialog even if a server "+
+ "has been specified in an applet parameter or on "+
+ "the command line",
+ false);
+
+ public static StringParameter vncServerName
+ = new StringParameter("Server",
+ "The VNC server <host>[:<dpyNum>] or "+
+ "<host>::<port>",
+ "");
+
+ /*
+ public static IntParameter vncServerPort
+ = new IntParameter("Port",
+ "The VNC server's port number, assuming it is on "+
+ "the host from which the applet was downloaded",
+ 0);
+ */
+
+ public static BoolParameter acceptBell
+ = new BoolParameter("AcceptBell",
+ "Produce a system beep when requested to by the server.",
+ true);
+
+ public static StringParameter via
+ = new StringParameter("Via",
+ "Automatically create an encrypted TCP tunnel to "+
+ "the gateway machine, then connect to the VNC host "+
+ "through that tunnel. By default, this option invokes "+
+ "SSH local port forwarding using the embedded JSch "+
+ "client, however an external SSH client may be specified "+
+ "using the \"-extSSH\" parameter. Note that when using "+
+ "the -via option, the VNC host machine name should be "+
+ "specified from the point of view of the gateway machine, "+
+ "e.g. \"localhost\" denotes the gateway, "+
+ "not the machine on which the viewer was launched. "+
+ "See the System Properties section below for "+
+ "information on configuring the -Via option.", "");
+
+ public static BoolParameter tunnel
+ = new BoolParameter("Tunnel",
+ "The -Tunnel command is basically a shorthand for the "+
+ "-via command when the VNC server and SSH gateway are "+
+ "one and the same. -Tunnel creates an SSH connection "+
+ "to the server and forwards the VNC through the tunnel "+
+ "without the need to specify anything else.", false);
+
+ public static BoolParameter extSSH
+ = new BoolParameter("extSSH",
+ "By default, SSH tunneling uses the embedded JSch client "+
+ "for tunnel creation. This option causes the client to "+
+ "invoke an external SSH client application for all tunneling "+
+ "operations. By default, \"/usr/bin/ssh\" is used, however "+
+ "the path to the external application may be specified using "+
+ "the -SSHClient option.", false);
+
+ public static StringParameter extSSHClient
+ = new StringParameter("extSSHClient",
+ "Specifies the path to an external SSH client application "+
+ "that is to be used for tunneling operations when the -extSSH "+
+ "option is in effect.", "/usr/bin/ssh");
+
+ public static StringParameter extSSHArgs
+ = new StringParameter("extSSHArgs",
+ "Specifies the arguments string or command template to be used "+
+ "by the external SSH client application when the -extSSH option "+
+ "is in effect. The string will be processed according to the same "+
+ "pattern substitution rules as the VNC_TUNNEL_CMD and VNC_VIA_CMD "+
+ "system properties, and can be used to override those in a more "+
+ "command-line friendly way. If not specified, then the appropriate "+
+ "VNC_TUNNEL_CMD or VNC_VIA_CMD command template will be used.", "");
+
+ public static StringParameter sshConfig
+ = new StringParameter("SSHConfig",
+ "Specifies the path to an OpenSSH configuration file that to "+
+ "be parsed by the embedded JSch SSH client during tunneling "+
+ "operations.", FileUtils.getHomeDir()+".ssh/config");
+
+ public static StringParameter sshKey
+ = new StringParameter("SSHKey",
+ "When using the Via or Tunnel options with the embedded SSH client, "+
+ "this parameter specifies the text of the SSH private key to use when "+
+ "authenticating with the SSH server. You can use \\n within the string "+
+ "to specify a new line.", "");
+
+ public static StringParameter sshKeyFile
+ = new StringParameter("SSHKeyFile",
+ "When using the Via or Tunnel options with the embedded SSH client, "+
+ "this parameter specifies a file that contains an SSH private key "+
+ "(or keys) to use when authenticating with the SSH server. If not "+
+ "specified, ~/.ssh/id_dsa or ~/.ssh/id_rsa will be used (if they exist). "+
+ "Otherwise, the client will fallback to prompting for an SSH password.",
+ "");
+
+ public static StringParameter sshKeyPass
+ = new StringParameter("SSHKeyPass",
+ "When using the Via or Tunnel options with the embedded SSH client, "+
+ "this parameter specifies the passphrase for the SSH key.", "");
+
+ public static BoolParameter customCompressLevel
+ = new BoolParameter("CustomCompressLevel",
+ "Use custom compression level. "+
+ "Default if CompressLevel is specified.",
+ false);
+
+ public static IntParameter compressLevel
+ = new IntParameter("CompressLevel",
+ "Use specified compression level "+
+ "0 = Low, 6 = High",
+ 1);
+
+ public static BoolParameter noJpeg
+ = new BoolParameter("NoJPEG",
+ "Disable lossy JPEG compression in Tight encoding.",
+ false);
+
+ public static IntParameter qualityLevel
+ = new IntParameter("QualityLevel",
+ "JPEG quality level. "+
+ "0 = Low, 9 = High",
+ 8);
+
+ private static final String IDENTIFIER_STRING = "TigerVNC Configuration file Version 1.0";
+
+ static VoidParameter[] parameterArray = {
+ CSecurityTLS.X509CA,
+ CSecurityTLS.X509CRL,
+ SecurityClient.secTypes,
+ autoSelect,
+ fullColor,
+ lowColorLevel,
+ preferredEncoding,
+ customCompressLevel,
+ compressLevel,
+ noJpeg,
+ qualityLevel,
+ fullScreen,
+ fullScreenAllMonitors,
+ desktopSize,
+ viewOnly,
+ shared,
+ acceptClipboard,
+ sendClipboard,
+ menuKey,
+ noLionFS,
+ useLocalCursor,
+ sendLocalUsername,
+ maxCutText,
+ scalingFactor,
+ acceptBell,
+ via,
+ tunnel,
+ extSSH,
+ extSSHClient,
+ extSSHArgs,
+ sshConfig,
+ sshKeyFile,
+ };
+
+
+ static LogWriter vlog = new LogWriter("Parameters");
+
+ public static void saveViewerParameters(String filename, String servername) {
+
+ // Write to the registry or a predefined file if no filename was specified.
+ String filepath;
+ if (filename == null || filename.isEmpty()) {
+ saveToReg(servername);
+ return;
+ /*
+ String homeDir = FileUtils.getVncHomeDir();
+ if (homeDir == null)
+ throw new Exception("Failed to read configuration file, "+
+ "can't obtain home directory path.");
+ filepath = homeDir.concat("default.tigervnc");
+ */
+ } else {
+ filepath = filename;
+ }
+
+ /* Write parameters to file */
+ File f = new File(filepath);
+ if (f.exists() && !f.canWrite())
+ throw new Exception(String.format("Failed to write configuration file,"+
+ "can't open %s", filepath));
+
+ PrintWriter pw = null;
+ try {
+ pw = new PrintWriter(f, "UTF-8");
+ } catch (java.lang.Exception e) {
+ throw new Exception(e.getMessage());
+ }
+
+ pw.println(IDENTIFIER_STRING);
+ pw.println("");
+
+ if (servername != null && !servername.isEmpty()) {
+ pw.println(String.format("ServerName=%s\n", servername));
+ updateConnHistory(servername);
+ }
+
+ for (int i = 0; i < parameterArray.length; i++) {
+ if (parameterArray[i] instanceof StringParameter) {
+ //if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName()))
+ pw.println(String.format("%s=%s",parameterArray[i].getName(),
+ parameterArray[i].getValueStr()));
+ } else if (parameterArray[i] instanceof IntParameter) {
+ //if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName()))
+ pw.println(String.format("%s=%s",parameterArray[i].getName(),
+ parameterArray[i].getValueStr()));
+ } else if (parameterArray[i] instanceof BoolParameter) {
+ //if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName()))
+ pw.println(String.format("%s=%s",parameterArray[i].getName(),
+ parameterArray[i].getValueStr()));
+ } else {
+ vlog.error(String.format("Unknown parameter type for parameter %s",
+ parameterArray[i].getName()));
+ }
+ }
+
+ pw.flush();
+ pw.close();
+ }
+
+ public static String loadViewerParameters(String filename) throws Exception {
+ String servername = "";
+
+ String filepath;
+ if (filename == null) {
+
+ return loadFromReg();
+
+ /*
+ String homeDir = FileUtils.getVncHomeDir();
+ if (homeDir == null)
+ throw new Exception("Failed to read configuration file, "+
+ "can't obtain home directory path.");
+ filepath = homeDir.concat("default.tigervnc");
+ */
+ } else {
+ filepath = filename;
+ }
+
+ /* Read parameters from file */
+ File f = new File(filepath);
+ if (!f.exists() || !f.canRead()) {
+ if (filename == null || filename.isEmpty())
+ return null;
+ throw new Exception(String.format("Failed to read configuration file, can't open %s",
+ filepath));
+ }
+
+ String line = "";
+ LineNumberReader reader;
+ try {
+ reader = new LineNumberReader(new FileReader(f));
+ } catch (FileNotFoundException e) {
+ throw new Exception(e.getMessage());
+ }
+
+ int lineNr = 0;
+ while (line != null) {
+
+ // Read the next line
+ try {
+ line = reader.readLine();
+ lineNr = reader.getLineNumber();
+ if (line == null)
+ break;
+ } catch (IOException e) {
+ throw new Exception(String.format("Failed to read line %d in file %s: %s",
+ lineNr, filepath, e.getMessage()));
+ }
+
+ // Make sure that the first line of the file has the file identifier string
+ if(lineNr == 1) {
+ if(line.equals(IDENTIFIER_STRING))
+ continue;
+ else
+ throw new Exception(String.format(new String("Configuration file %s is in an invalid format"), filename));
+ }
+
+ // Skip empty lines and comments
+ if (line.trim().isEmpty() || line.trim().startsWith("#"))
+ continue;
+
+ // Find the parameter value
+ int idx = line.indexOf("=");
+ if (idx == -1) {
+ vlog.error(String.format("Failed to read line %d in file %s: %s",
+ lineNr, filename, "Invalid format"));
+ continue;
+ }
+ String value = line.substring(idx+1).trim();
+ boolean invalidParameterName = true; // Will be set to false below if
+ // the line contains a valid name.
+
+ if (line.substring(0,idx).trim().equalsIgnoreCase("ServerName")) {
+ if (value.length() > 256) {
+ vlog.error(String.format("Failed to read line %d in file %s: %s",
+ lineNr, filepath, "Invalid format or too large value"));
+ continue;
+ }
+ servername = value;
+ invalidParameterName = false;
+ } else {
+ for (int i = 0; i < parameterArray.length; i++) {
+ if (parameterArray[i] instanceof StringParameter) {
+ if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName())) {
+ if (value.length() > 256) {
+ vlog.error(String.format("Failed to read line %d in file %s: %s",
+ lineNr, filepath, "Invalid format or too large value"));
+ continue;
+ }
+ ((StringParameter)parameterArray[i]).setParam(value);
+ invalidParameterName = false;
+ }
+ } else if (parameterArray[i] instanceof IntParameter) {
+ if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName())) {
+ ((IntParameter)parameterArray[i]).setParam(value);
+ invalidParameterName = false;
+ }
+ } else if (parameterArray[i] instanceof BoolParameter) {
+ if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName())) {
+ ((BoolParameter)parameterArray[i]).setParam(value);
+ invalidParameterName = false;
+ }
+ } else {
+ vlog.error(String.format("Unknown parameter type for parameter %s",
+ parameterArray[i].getName()));
+
+ }
+ }
+ }
+
+ if (invalidParameterName)
+ vlog.info(String.format("Unknown parameter %s on line %d in file %s",
+ line, lineNr, filepath));
+ }
+ try {
+ reader.close();
+ } catch (IOException e) {
+ vlog.info(e.getMessage());
+ } finally {
+ try {
+ if (reader != null)
+ reader.close();
+ } catch (IOException e) { }
+ }
+
+ return servername;
+ }
+
+ public static void saveToReg(String servername) {
+ String hKey = "global";
+
+ if (servername != null && !servername.isEmpty()) {
+ UserPreferences.set(hKey, "ServerName", servername);
+ updateConnHistory(servername);
+ }
+
+ for (int i = 0; i < parameterArray.length; i++) {
+ if (parameterArray[i] instanceof StringParameter) {
+ UserPreferences.set(hKey, parameterArray[i].getName(),
+ parameterArray[i].getValueStr());
+ } else if (parameterArray[i] instanceof IntParameter) {
+ UserPreferences.set(hKey, parameterArray[i].getName(),
+ ((IntParameter)parameterArray[i]).getValue());
+ } else if (parameterArray[i] instanceof BoolParameter) {
+ UserPreferences.set(hKey, parameterArray[i].getName(),
+ ((BoolParameter)parameterArray[i]).getValue());
+ } else {
+ vlog.error(String.format("Unknown parameter type for parameter %s",
+ parameterArray[i].getName()));
+ }
+ }
+
+ UserPreferences.save(hKey);
+ }
+
+ public static String loadFromReg() {
+
+ String hKey = "global";
+
+ String servername = UserPreferences.get(hKey, "ServerName");
+ if (servername == null)
+ servername = "";
+
+ for (int i = 0; i < parameterArray.length; i++) {
+ if (parameterArray[i] instanceof StringParameter) {
+ if (UserPreferences.get(hKey, parameterArray[i].getName()) != null) {
+ String stringValue =
+ UserPreferences.get(hKey, parameterArray[i].getName());
+ ((StringParameter)parameterArray[i]).setParam(stringValue);
+ }
+ } else if (parameterArray[i] instanceof IntParameter) {
+ if (UserPreferences.get(hKey, parameterArray[i].getName()) != null) {
+ int intValue =
+ UserPreferences.getInt(hKey, parameterArray[i].getName());
+ ((IntParameter)parameterArray[i]).setParam(intValue);
+ }
+ } else if (parameterArray[i] instanceof BoolParameter) {
+ if (UserPreferences.get(hKey, parameterArray[i].getName()) != null) {
+ boolean booleanValue =
+ UserPreferences.getBool(hKey, parameterArray[i].getName());
+ ((BoolParameter)parameterArray[i]).setParam(booleanValue);
+ }
+ } else {
+ vlog.error(String.format("Unknown parameter type for parameter %s",
+ parameterArray[i].getName()));
+ }
+ }
+
+ return servername;
+ }
+
+ public static String loadAppletParameters(VncViewer applet) {
+ String servername = applet.getParameter("Server");
+ String serverport = applet.getParameter("Port");
+ String embedParam = applet.getParameter("Embed");
+
+ if (servername == null)
+ servername = applet.getCodeBase().getHost();
+
+ if (serverport != null)
+ servername = servername.concat("::"+serverport);
+ else
+ servername = servername.concat("::5900");
+
+ if (embedParam != null)
+ embed.setParam(embedParam);
+
+ for (int i = 0; i < parameterArray.length; i++) {
+ String value = applet.getParameter(parameterArray[i].getName());
+ if (value == null)
+ continue;
+ if (parameterArray[i] instanceof StringParameter) {
+ if (value.length() > 256) {
+ vlog.error(String.format("Failed to read applet parameter %s: %s",
+ parameterArray[i].getName(),
+ "Invalid format or too large value"));
+ continue;
+ }
+ ((StringParameter)parameterArray[i]).setParam(value);
+ } else if (parameterArray[i] instanceof IntParameter) {
+ ((IntParameter)parameterArray[i]).setParam(value);
+ } else if (parameterArray[i] instanceof BoolParameter) {
+ ((BoolParameter)parameterArray[i]).setParam(value);
+ } else {
+ vlog.error(String.format("Unknown parameter type for parameter %s",
+ parameterArray[i].getName()));
+
+ }
+ }
+
+ return servername;
+ }
+
+ private static void updateConnHistory(String serverName) {
+ String hKey = "ServerDialog";
+ if (serverName != null && !serverName.isEmpty()) {
+ String valueStr = UserPreferences.get(hKey, "history");
+ String t = (valueStr == null) ? "" : valueStr;
+ StringTokenizer st = new StringTokenizer(t, ",");
+ StringBuffer sb = new StringBuffer().append(serverName);
+ while (st.hasMoreTokens()) {
+ String str = st.nextToken();
+ if (!str.equals(serverName) && !str.equals(""))
+ sb.append(',').append(str);
+ }
+ UserPreferences.set(hKey, "history", sb.toString());
+ UserPreferences.save(hKey);
+ }
+ }
+
+}