You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Parameters.java 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. /* Copyright (C) 2016-2019 Brian P. Hinz
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  16. * USA.
  17. */
  18. package com.tigervnc.vncviewer;
  19. import java.io.File;
  20. import java.io.FileNotFoundException;
  21. import java.io.FileReader;
  22. import java.io.IOException;
  23. import java.io.LineNumberReader;
  24. import java.io.PrintWriter;
  25. import java.util.StringTokenizer;
  26. import com.tigervnc.rfb.*;
  27. import com.tigervnc.rfb.Exception;
  28. public class Parameters {
  29. public static BoolParameter noLionFS
  30. = new BoolParameter("NoLionFS",
  31. "On Mac systems, setting this parameter will force the use of the old "+
  32. "(pre-Lion) full-screen mode, even if the viewer is running on OS X 10.7 "+
  33. "Lion or later.",
  34. false);
  35. public static BoolParameter dotWhenNoCursor
  36. = new BoolParameter("DotWhenNoCursor",
  37. "Show the dot cursor when the server sends an invisible cursor",
  38. false);
  39. public static BoolParameter sendLocalUsername
  40. = new BoolParameter("SendLocalUsername",
  41. "Send the local username for SecurityTypes "+
  42. "such as Plain rather than prompting",
  43. true);
  44. public static StringParameter passwordFile
  45. = new StringParameter("PasswordFile",
  46. "Password file for VNC authentication",
  47. "");
  48. public static AliasParameter passwd
  49. = new AliasParameter("passwd",
  50. "Alias for PasswordFile",
  51. passwordFile);
  52. public static BoolParameter autoSelect
  53. = new BoolParameter("AutoSelect",
  54. "Auto select pixel format and encoding",
  55. true);
  56. public static BoolParameter fullColor
  57. = new BoolParameter("FullColor",
  58. "Use full color - otherwise 6-bit colour is used "+
  59. "until AutoSelect decides the link is fast enough",
  60. true);
  61. public static AliasParameter fullColorAlias
  62. = new AliasParameter("FullColour",
  63. "Alias for FullColor",
  64. Parameters.fullColor);
  65. public static IntParameter lowColorLevel
  66. = new IntParameter("LowColorLevel",
  67. "Color level to use on slow connections. "+
  68. "0 = Very Low, 1 = Low, 2 = Medium",
  69. 2);
  70. public static AliasParameter lowColorLevelAlias
  71. = new AliasParameter("LowColourLevel",
  72. "Alias for LowColorLevel",
  73. lowColorLevel);
  74. public static StringParameter preferredEncoding
  75. = new StringParameter("PreferredEncoding",
  76. "Preferred encoding to use (Tight, ZRLE, "+
  77. "hextile or raw) - implies AutoSelect=0",
  78. "Tight");
  79. public static BoolParameter remoteResize
  80. = new BoolParameter("RemoteResize",
  81. "Dynamically resize the remote desktop size as "+
  82. "the size of the local client window changes. "+
  83. "(Does not work with all servers)",
  84. true);
  85. public static BoolParameter viewOnly
  86. = new BoolParameter("ViewOnly",
  87. "Don't send any mouse or keyboard events to the server",
  88. false);
  89. public static BoolParameter shared
  90. = new BoolParameter("Shared",
  91. "Don't disconnect other viewers upon "+
  92. "connection - share the desktop instead",
  93. false);
  94. public static BoolParameter maximize
  95. = new BoolParameter("Maximize",
  96. "Maximize viewer window",
  97. false);
  98. public static BoolParameter fullScreen
  99. = new BoolParameter("FullScreen",
  100. "Enable full screen",
  101. false);
  102. public static BoolParameter fullScreenAllMonitors
  103. = new BoolParameter("FullScreenAllMonitors",
  104. "Enable full screen over all monitors",
  105. true);
  106. public static BoolParameter acceptClipboard
  107. = new BoolParameter("AcceptClipboard",
  108. "Accept clipboard changes from the server",
  109. true);
  110. public static BoolParameter sendClipboard
  111. = new BoolParameter("SendClipboard",
  112. "Send clipboard changes to the server",
  113. true);
  114. public static IntParameter maxCutText
  115. = new IntParameter("MaxCutText",
  116. "Maximum permitted length of an outgoing clipboard update",
  117. 262144);
  118. public static StringParameter menuKey
  119. = new StringParameter("MenuKey",
  120. "The key which brings up the popup menu",
  121. "F8");
  122. public static StringParameter desktopSize
  123. = new StringParameter("DesktopSize",
  124. "Reconfigure desktop size on the server on connect (if possible)",
  125. "");
  126. public static BoolParameter listenMode
  127. = new BoolParameter("listen",
  128. "Listen for connections from VNC servers",
  129. false);
  130. public static StringParameter scalingFactor
  131. = new StringParameter("ScalingFactor",
  132. "Reduce or enlarge the remote desktop image. "+
  133. "The value is interpreted as a scaling factor "+
  134. "in percent. If the parameter is set to "+
  135. "\"Auto\", then automatic scaling is "+
  136. "performed. Auto-scaling tries to choose a "+
  137. "scaling factor in such a way that the whole "+
  138. "remote desktop will fit on the local screen. "+
  139. "If the parameter is set to \"FixedRatio\", "+
  140. "then automatic scaling is performed, but the "+
  141. "original aspect ratio is preserved.",
  142. "100");
  143. public static BoolParameter alwaysShowServerDialog
  144. = new BoolParameter("AlwaysShowServerDialog",
  145. "Always show the server dialog even if a server has been "+
  146. "specified in an applet parameter or on the command line",
  147. false);
  148. public static BoolParameter acceptBell
  149. = new BoolParameter("AcceptBell",
  150. "Produce a system beep when requested to by the server.",
  151. true);
  152. public static StringParameter via
  153. = new StringParameter("Via",
  154. "Automatically create an encrypted TCP tunnel to "+
  155. "the gateway machine, then connect to the VNC host "+
  156. "through that tunnel. By default, this option invokes "+
  157. "SSH local port forwarding using the embedded JSch "+
  158. "client, however an external SSH client may be specified "+
  159. "using the \"-extSSH\" parameter. Note that when using "+
  160. "the -via option, the VNC host machine name should be "+
  161. "specified from the point of view of the gateway machine, "+
  162. "e.g. \"localhost\" denotes the gateway, "+
  163. "not the machine on which the viewer was launched. "+
  164. "See the System Properties section below for "+
  165. "information on configuring the -Via option.", "");
  166. public static BoolParameter tunnel
  167. = new BoolParameter("Tunnel",
  168. "The -Tunnel command is basically a shorthand for the "+
  169. "-via command when the VNC server and SSH gateway are "+
  170. "one and the same. -Tunnel creates an SSH connection "+
  171. "to the server and forwards the VNC through the tunnel "+
  172. "without the need to specify anything else.", false);
  173. public static BoolParameter extSSH
  174. = new BoolParameter("extSSH",
  175. "By default, SSH tunneling uses the embedded JSch client "+
  176. "for tunnel creation. This option causes the client to "+
  177. "invoke an external SSH client application for all tunneling "+
  178. "operations. By default, \"/usr/bin/ssh\" is used, however "+
  179. "the path to the external application may be specified using "+
  180. "the -SSHClient option.", false);
  181. public static StringParameter extSSHClient
  182. = new StringParameter("extSSHClient",
  183. "Specifies the path to an external SSH client application "+
  184. "that is to be used for tunneling operations when the -extSSH "+
  185. "option is in effect.", "/usr/bin/ssh");
  186. public static StringParameter extSSHArgs
  187. = new StringParameter("extSSHArgs",
  188. "Specifies the arguments string or command template to be used "+
  189. "by the external SSH client application when the -extSSH option "+
  190. "is in effect. The string will be processed according to the same "+
  191. "pattern substitution rules as the VNC_TUNNEL_CMD and VNC_VIA_CMD "+
  192. "system properties, and can be used to override those in a more "+
  193. "command-line friendly way. If not specified, then the appropriate "+
  194. "VNC_TUNNEL_CMD or VNC_VIA_CMD command template will be used.", "");
  195. public static StringParameter sshConfig
  196. = new StringParameter("SSHConfig",
  197. "Specifies the path to an OpenSSH configuration file that to "+
  198. "be parsed by the embedded JSch SSH client during tunneling "+
  199. "operations.", FileUtils.getHomeDir()+".ssh/config");
  200. public static StringParameter sshKey
  201. = new StringParameter("SSHKey",
  202. "When using the Via or Tunnel options with the embedded SSH client, "+
  203. "this parameter specifies the text of the SSH private key to use when "+
  204. "authenticating with the SSH server. You can use \\n within the string "+
  205. "to specify a new line.", "");
  206. public static StringParameter sshKeyFile
  207. = new StringParameter("SSHKeyFile",
  208. "When using the Via or Tunnel options with the embedded SSH client, "+
  209. "this parameter specifies a file that contains an SSH private key "+
  210. "(or keys) to use when authenticating with the SSH server. If not "+
  211. "specified, ~/.ssh/id_dsa or ~/.ssh/id_rsa will be used (if they exist). "+
  212. "Otherwise, the client will fallback to prompting for an SSH password.",
  213. "");
  214. public static StringParameter sshKeyPass
  215. = new StringParameter("SSHKeyPass",
  216. "When using the Via or Tunnel options with the embedded SSH client, "+
  217. "this parameter specifies the passphrase for the SSH key.", "");
  218. public static BoolParameter customCompressLevel
  219. = new BoolParameter("CustomCompressLevel",
  220. "Use custom compression level. Default if CompressLevel is specified.",
  221. false);
  222. public static IntParameter compressLevel
  223. = new IntParameter("CompressLevel",
  224. "Use specified lossless compression level. 0 = Low, 9 = High. Default is 2.",
  225. 2);
  226. public static BoolParameter noJpeg
  227. = new BoolParameter("NoJPEG",
  228. "Disable lossy JPEG compression in Tight encoding.",
  229. false);
  230. public static IntParameter qualityLevel
  231. = new IntParameter("QualityLevel",
  232. "JPEG quality level. 0 = Low, 9 = High",
  233. 8);
  234. private static final String IDENTIFIER_STRING
  235. = "TigerVNC Configuration file Version 1.0";
  236. static VoidParameter[] parameterArray = {
  237. CSecurityTLS.X509CA,
  238. CSecurityTLS.X509CRL,
  239. SecurityClient.secTypes,
  240. dotWhenNoCursor,
  241. autoSelect,
  242. fullColor,
  243. lowColorLevel,
  244. preferredEncoding,
  245. customCompressLevel,
  246. compressLevel,
  247. noJpeg,
  248. qualityLevel,
  249. maximize,
  250. fullScreen,
  251. fullScreenAllMonitors,
  252. desktopSize,
  253. remoteResize,
  254. viewOnly,
  255. shared,
  256. acceptClipboard,
  257. sendClipboard,
  258. menuKey,
  259. noLionFS,
  260. sendLocalUsername,
  261. maxCutText,
  262. scalingFactor,
  263. acceptBell,
  264. via,
  265. tunnel,
  266. extSSH,
  267. extSSHClient,
  268. extSSHArgs,
  269. sshConfig,
  270. sshKeyFile,
  271. };
  272. static LogWriter vlog = new LogWriter("Parameters");
  273. public static void saveViewerParameters(String filename, String servername) {
  274. // Write to the registry or a predefined file if no filename was specified.
  275. String filepath;
  276. if (filename == null || filename.isEmpty()) {
  277. saveToReg(servername);
  278. return;
  279. } else {
  280. filepath = filename;
  281. }
  282. /* Write parameters to file */
  283. File f = new File(filepath);
  284. if (f.exists() && !f.canWrite())
  285. throw new Exception(String.format("Failed to write configuration file,"+
  286. "can't open %s", filepath));
  287. PrintWriter pw = null;
  288. try {
  289. pw = new PrintWriter(f, "UTF-8");
  290. } catch (java.lang.Exception e) {
  291. throw new Exception(e.getMessage());
  292. }
  293. pw.println(IDENTIFIER_STRING);
  294. pw.println("");
  295. if (servername != null && !servername.isEmpty()) {
  296. pw.println(String.format("ServerName=%s\n", servername));
  297. updateConnHistory(servername);
  298. }
  299. for (int i = 0; i < parameterArray.length; i++) {
  300. if (parameterArray[i] instanceof StringParameter) {
  301. //if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName()))
  302. pw.println(String.format("%s=%s",parameterArray[i].getName(),
  303. parameterArray[i].getValueStr()));
  304. } else if (parameterArray[i] instanceof IntParameter) {
  305. //if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName()))
  306. pw.println(String.format("%s=%s",parameterArray[i].getName(),
  307. parameterArray[i].getValueStr()));
  308. } else if (parameterArray[i] instanceof BoolParameter) {
  309. //if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName()))
  310. pw.println(String.format("%s=%s",parameterArray[i].getName(),
  311. parameterArray[i].getValueStr()));
  312. } else {
  313. vlog.error(String.format("Unknown parameter type for parameter %s",
  314. parameterArray[i].getName()));
  315. }
  316. }
  317. pw.flush();
  318. pw.close();
  319. }
  320. public static String loadViewerParameters(String filename) throws Exception {
  321. String servername = "";
  322. String filepath;
  323. if (filename == null) {
  324. return loadFromReg();
  325. } else {
  326. filepath = filename;
  327. }
  328. /* Read parameters from file */
  329. File f = new File(filepath);
  330. if (!f.exists() || !f.canRead()) {
  331. if (filename == null || filename.isEmpty())
  332. return null;
  333. throw new Exception(String.format("Failed to read configuration file, can't open %s",
  334. filepath));
  335. }
  336. String line = "";
  337. LineNumberReader reader;
  338. try {
  339. reader = new LineNumberReader(new FileReader(f));
  340. } catch (FileNotFoundException e) {
  341. throw new Exception(e.getMessage());
  342. }
  343. int lineNr = 0;
  344. while (line != null) {
  345. // Read the next line
  346. try {
  347. line = reader.readLine();
  348. lineNr = reader.getLineNumber();
  349. if (line == null)
  350. break;
  351. } catch (IOException e) {
  352. throw new Exception(String.format("Failed to read line %d in file %s: %s",
  353. lineNr, filepath, e.getMessage()));
  354. }
  355. // Make sure that the first line of the file has the file identifier string
  356. if(lineNr == 1) {
  357. if(line.equals(IDENTIFIER_STRING))
  358. continue;
  359. else
  360. throw new Exception(String.format("Configuration file %s is in an invalid format", filename));
  361. }
  362. // Skip empty lines and comments
  363. if (line.trim().isEmpty() || line.trim().startsWith("#"))
  364. continue;
  365. // Find the parameter value
  366. int idx = line.indexOf("=");
  367. if (idx == -1) {
  368. vlog.error(String.format("Failed to read line %d in file %s: %s",
  369. lineNr, filename, "Invalid format"));
  370. continue;
  371. }
  372. String value = line.substring(idx+1).trim();
  373. boolean invalidParameterName = true; // Will be set to false below if
  374. // the line contains a valid name.
  375. if (line.substring(0,idx).trim().equalsIgnoreCase("ServerName")) {
  376. if (value.length() > 256) {
  377. vlog.error(String.format("Failed to read line %d in file %s: %s",
  378. lineNr, filepath, "Invalid format or too large value"));
  379. continue;
  380. }
  381. servername = value;
  382. invalidParameterName = false;
  383. } else {
  384. for (int i = 0; i < parameterArray.length; i++) {
  385. if (parameterArray[i] instanceof StringParameter) {
  386. if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName())) {
  387. if (value.length() > 256) {
  388. vlog.error(String.format("Failed to read line %d in file %s: %s",
  389. lineNr, filepath, "Invalid format or too large value"));
  390. continue;
  391. }
  392. ((StringParameter)parameterArray[i]).setParam(value);
  393. invalidParameterName = false;
  394. }
  395. } else if (parameterArray[i] instanceof IntParameter) {
  396. if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName())) {
  397. ((IntParameter)parameterArray[i]).setParam(value);
  398. invalidParameterName = false;
  399. }
  400. } else if (parameterArray[i] instanceof BoolParameter) {
  401. if (line.substring(0,idx).trim().equalsIgnoreCase(parameterArray[i].getName())) {
  402. ((BoolParameter)parameterArray[i]).setParam(value);
  403. invalidParameterName = false;
  404. }
  405. } else {
  406. vlog.error(String.format("Unknown parameter type for parameter %s",
  407. parameterArray[i].getName()));
  408. }
  409. }
  410. }
  411. if (invalidParameterName)
  412. vlog.info(String.format("Unknown parameter %s on line %d in file %s",
  413. line, lineNr, filepath));
  414. }
  415. try {
  416. reader.close();
  417. } catch (IOException e) {
  418. vlog.info(e.getMessage());
  419. } finally {
  420. try {
  421. if (reader != null)
  422. reader.close();
  423. } catch (IOException e) { }
  424. }
  425. return servername;
  426. }
  427. public static void saveToReg(String servername) {
  428. String hKey = "global";
  429. if (servername != null && !servername.isEmpty()) {
  430. UserPreferences.set(hKey, "ServerName", servername);
  431. updateConnHistory(servername);
  432. }
  433. for (int i = 0; i < parameterArray.length; i++) {
  434. if (parameterArray[i] instanceof StringParameter) {
  435. UserPreferences.set(hKey, parameterArray[i].getName(),
  436. parameterArray[i].getValueStr());
  437. } else if (parameterArray[i] instanceof IntParameter) {
  438. UserPreferences.set(hKey, parameterArray[i].getName(),
  439. ((IntParameter)parameterArray[i]).getValue());
  440. } else if (parameterArray[i] instanceof BoolParameter) {
  441. UserPreferences.set(hKey, parameterArray[i].getName(),
  442. ((BoolParameter)parameterArray[i]).getValue());
  443. } else {
  444. vlog.error(String.format("Unknown parameter type for parameter %s",
  445. parameterArray[i].getName()));
  446. }
  447. }
  448. UserPreferences.save(hKey);
  449. }
  450. public static String loadFromReg() {
  451. String hKey = "global";
  452. String servername = UserPreferences.get(hKey, "ServerName");
  453. if (servername == null)
  454. servername = "";
  455. for (int i = 0; i < parameterArray.length; i++) {
  456. if (parameterArray[i] instanceof StringParameter) {
  457. if (UserPreferences.get(hKey, parameterArray[i].getName()) != null) {
  458. String stringValue =
  459. UserPreferences.get(hKey, parameterArray[i].getName());
  460. ((StringParameter)parameterArray[i]).setParam(stringValue);
  461. }
  462. } else if (parameterArray[i] instanceof IntParameter) {
  463. if (UserPreferences.get(hKey, parameterArray[i].getName()) != null) {
  464. int intValue =
  465. UserPreferences.getInt(hKey, parameterArray[i].getName());
  466. ((IntParameter)parameterArray[i]).setParam(intValue);
  467. }
  468. } else if (parameterArray[i] instanceof BoolParameter) {
  469. if (UserPreferences.get(hKey, parameterArray[i].getName()) != null) {
  470. boolean booleanValue =
  471. UserPreferences.getBool(hKey, parameterArray[i].getName());
  472. ((BoolParameter)parameterArray[i]).setParam(booleanValue);
  473. }
  474. } else {
  475. vlog.error(String.format("Unknown parameter type for parameter %s",
  476. parameterArray[i].getName()));
  477. }
  478. }
  479. return servername;
  480. }
  481. private static void updateConnHistory(String serverName) {
  482. String hKey = "ServerDialog";
  483. if (serverName != null && !serverName.isEmpty()) {
  484. String valueStr = UserPreferences.get(hKey, "history");
  485. String t = (valueStr == null) ? "" : valueStr;
  486. StringTokenizer st = new StringTokenizer(t, ",");
  487. StringBuffer sb = new StringBuffer().append(serverName);
  488. while (st.hasMoreTokens()) {
  489. String str = st.nextToken();
  490. if (!str.equals(serverName) && !str.equals(""))
  491. sb.append(',').append(str);
  492. }
  493. UserPreferences.set(hKey, "history", sb.toString());
  494. UserPreferences.save(hKey);
  495. }
  496. }
  497. }