blob: 1151a7c8e30e1a8d17205258d4bae9fb81549181 [file] [log] [blame]
Pierre Ossman5156d5e2011-03-09 09:42:34 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
Peter Åstrand8a2b0812012-08-08 11:49:01 +00003 * Copyright 2012 Samuel Mannehed <samuel@cendio.se> for Cendio AB
Pierre Ossman5156d5e2011-03-09 09:42:34 +00004 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 */
20
Peter Åstrandc359f362011-08-23 12:04:46 +000021#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
Peter Åstrand8a2b0812012-08-08 11:49:01 +000025#ifdef HAVE_GNUTLS
26#include <rfb/CSecurityTLS.h>
27#endif
28
29#ifdef _WIN32
30#include <windows.h>
31#include <tchar.h>
32#endif
33
Pierre Ossman5156d5e2011-03-09 09:42:34 +000034#include "parameters.h"
35
Peter Åstrand8a2b0812012-08-08 11:49:01 +000036#include <os/os.h>
37#include <rfb/Exception.h>
38#include <rfb/LogWriter.h>
39#include <rfb/SecurityClient.h>
40
41#include <FL/fl_utf8.h>
42
43#include <stdio.h>
44#include <string.h>
45#include <limits.h>
Pierre Ossman1bfbcb52014-12-03 14:03:29 +010046#include <errno.h>
Peter Åstrand8a2b0812012-08-08 11:49:01 +000047
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +020048#include "i18n.h"
49
Pierre Ossman5156d5e2011-03-09 09:42:34 +000050using namespace rfb;
51
Peter Åstrand8a2b0812012-08-08 11:49:01 +000052static LogWriter vlog("Parameters");
53
54
Pierre Ossman4c8e3112011-06-08 17:21:48 +000055IntParameter pointerEventInterval("PointerEventInterval",
56 "Time in milliseconds to rate-limit"
57 " successive pointer events", 0);
Pierre Ossman5156d5e2011-03-09 09:42:34 +000058BoolParameter dotWhenNoCursor("DotWhenNoCursor",
59 "Show the dot cursor when the server sends an "
Pierre Ossman93f37742011-06-09 08:35:34 +000060 "invisible cursor", false);
Pierre Ossman5156d5e2011-03-09 09:42:34 +000061
62StringParameter passwordFile("PasswordFile",
63 "Password file for VNC authentication", "");
64AliasParameter passwd("passwd", "Alias for PasswordFile", &passwordFile);
65
66BoolParameter autoSelect("AutoSelect",
67 "Auto select pixel format and encoding. "
68 "Default if PreferredEncoding and FullColor are not specified.",
69 true);
70BoolParameter fullColour("FullColor",
71 "Use full color", true);
72AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
73IntParameter lowColourLevel("LowColorLevel",
74 "Color level to use on slow connections. "
75 "0 = Very Low (8 colors), 1 = Low (64 colors), "
76 "2 = Medium (256 colors)", 2);
77AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
78StringParameter preferredEncoding("PreferredEncoding",
79 "Preferred encoding to use (Tight, ZRLE, Hextile or"
80 " Raw)", "Tight");
81BoolParameter customCompressLevel("CustomCompressLevel",
82 "Use custom compression level. "
83 "Default if CompressLevel is specified.", false);
84IntParameter compressLevel("CompressLevel",
DRCba7bc512011-08-17 02:30:34 +000085 "Use specified compression level 0 = Low, 6 = High",
Pierre Ossman701ad682011-11-20 15:39:17 +000086 2);
Pierre Ossman5156d5e2011-03-09 09:42:34 +000087BoolParameter noJpeg("NoJPEG",
88 "Disable lossy JPEG compression in Tight encoding.",
89 false);
90IntParameter qualityLevel("QualityLevel",
91 "JPEG quality level. 0 = Low, 9 = High",
92 8);
93
Peter Åstrand49b11572012-08-01 08:09:09 +000094BoolParameter maximize("Maximize", "Maximize viewer window", false);
Pierre Ossman5156d5e2011-03-09 09:42:34 +000095BoolParameter fullScreen("FullScreen", "Full screen mode", false);
Pierre Ossmanaae38912012-07-13 11:22:55 +000096BoolParameter fullScreenAllMonitors("FullScreenAllMonitors",
97 "Enable full screen over all monitors",
98 true);
Pierre Ossman5156d5e2011-03-09 09:42:34 +000099StringParameter desktopSize("DesktopSize",
100 "Reconfigure desktop size on the server on "
101 "connect (if possible)", "");
Peter Åstrandb182a9e2012-08-27 07:28:08 +0000102StringParameter geometry("geometry",
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200103 "Specify size and position of viewer window", "");
Pierre Ossman2a7a8d62013-02-15 08:33:39 +0000104
105BoolParameter listenMode("listen", "Listen for connections from VNC servers", false);
106
Pierre Ossmanff473402012-07-04 11:27:47 +0000107BoolParameter remoteResize("RemoteResize",
108 "Dynamically resize the remote desktop size as "
109 "the size of the local client window changes. "
110 "(Does not work with all servers)", true);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000111
112BoolParameter viewOnly("ViewOnly",
113 "Don't send any mouse or keyboard events to the server",
114 false);
115BoolParameter shared("Shared",
116 "Don't disconnect other viewers upon connection - "
117 "share the desktop instead",
118 false);
119
120BoolParameter acceptClipboard("AcceptClipboard",
121 "Accept clipboard changes from the server",
122 true);
Pierre Ossmanf862c2e2016-03-29 14:15:38 +0200123BoolParameter setPrimary("SetPrimary",
124 "Set the primary selection as well as the "
125 "clipboard selection", true);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000126BoolParameter sendClipboard("SendClipboard",
127 "Send clipboard changes to the server", true);
Pierre Ossmanf7fef922015-12-10 21:24:08 +0100128#if !defined(WIN32) && !defined(__APPLE__)
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000129BoolParameter sendPrimary("SendPrimary",
130 "Send the primary selection and cut buffer to the "
131 "server as well as the clipboard selection",
132 true);
Pierre Ossmanf7fef922015-12-10 21:24:08 +0100133#endif
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000134
135StringParameter menuKey("MenuKey", "The key which brings up the popup menu",
136 "F8");
137
Pierre Ossman407a5c32011-05-26 14:48:29 +0000138BoolParameter fullscreenSystemKeys("FullscreenSystemKeys",
139 "Pass special keys (like Alt+Tab) directly "
140 "to the server when in full screen mode.",
141 true);
142
Adam Tkac8ac4b302013-01-23 13:55:46 +0000143#ifndef WIN32
144StringParameter via("via", "Gateway to tunnel via", "");
145#endif
146
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100147static const char* IDENTIFIER_STRING = "TigerVNC Configuration file Version 1.0";
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000148
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100149static VoidParameter* parameterArray[] = {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000150#ifdef HAVE_GNUTLS
Pierre Ossman3d2a84b2014-09-17 16:45:35 +0200151 &CSecurityTLS::X509CA,
152 &CSecurityTLS::X509CRL,
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000153#endif // HAVE_GNUTLS
154 &SecurityClient::secTypes,
155 &dotWhenNoCursor,
156 &autoSelect,
157 &fullColour,
158 &lowColourLevel,
159 &preferredEncoding,
160 &customCompressLevel,
161 &compressLevel,
162 &noJpeg,
163 &qualityLevel,
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000164 &fullScreen,
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000165 &fullScreenAllMonitors,
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000166 &desktopSize,
Peter Åstrandb182a9e2012-08-27 07:28:08 +0000167 &geometry,
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000168 &remoteResize,
169 &viewOnly,
170 &shared,
171 &acceptClipboard,
172 &sendClipboard,
Pierre Ossmanf7fef922015-12-10 21:24:08 +0100173#if !defined(WIN32) && !defined(__APPLE__)
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000174 &sendPrimary,
Pierre Ossmanf7fef922015-12-10 21:24:08 +0100175#endif
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000176 &menuKey,
177 &fullscreenSystemKeys
178};
179
180// Encoding Table
181static struct {
182 const char first;
183 const char second;
Pierre Ossman6e538b42015-03-03 16:48:01 +0100184} replaceMap[] = { { '\n', 'n' },
185 { '\r', 'r' } };
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000186
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100187static bool encodeValue(const char* val, char* dest, size_t destSize) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000188
189 bool normalCharacter = true;
190 size_t pos = 0;
191
Pierre Ossmana9af1f12015-06-17 10:47:28 +0200192 for (size_t i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000193
194 // Check for sequences which will need encoding
195 if (val[i] == '\\') {
196
197 strncpy(dest+pos, "\\\\", 2);
198 pos++;
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100199 if (pos >= destSize)
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200200 return false;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000201
202 } else {
203
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100204 for (size_t j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000205
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200206 if (val[i] == replaceMap[j].first) {
207 dest[pos] = '\\';
208 pos++;
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100209 if (pos >= destSize)
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200210 return false;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000211
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200212 dest[pos] = replaceMap[j].second;
213 normalCharacter = false;
214 break;
215 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000216
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200217 if (normalCharacter) {
218 dest[pos] = val[i];
219 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000220 }
221 }
222 normalCharacter = true; // Reset for next loop
223
224 pos++;
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100225 if (pos >= destSize)
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000226 return false;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000227 }
228
229 dest[pos] = '\0';
230 return true;
231}
232
233
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100234static bool decodeValue(const char* val, char* dest, size_t destSize) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000235
236 size_t pos = 0;
237 bool escapedCharacter = false;
238
Pierre Ossmana9af1f12015-06-17 10:47:28 +0200239 for (size_t i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000240
241 // Check for escape sequences
242 if (val[i] == '\\') {
243
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100244 for (size_t j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) {
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200245 if (val[i+1] == replaceMap[j].second) {
246 dest[pos] = replaceMap[j].first;
247 escapedCharacter = true;
248 pos--;
249 break;
250 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000251 }
252
253 if (!escapedCharacter) {
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200254 if (val[i+1] == '\\') {
255 dest[pos] = val[i];
256 i++;
257 } else {
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200258 return false;
259 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000260 }
261
262 } else {
263 dest[pos] = val[i];
264 }
265
266 escapedCharacter = false; // Reset for next loop
267 pos++;
268 if (pos >= destSize) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000269 return false;
270 }
271 }
272
273 dest[pos] = '\0';
274 return true;
275}
276
277
278#ifdef _WIN32
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100279static void setKeyString(const char *_name, const char *_value, HKEY* hKey) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000280
281 const DWORD buffersize = 256;
282
283 wchar_t name[buffersize];
284 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
285 if (size >= buffersize) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100286 vlog.error(_("The name of the parameter %s was too large to write to the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000287 return;
288 }
289
290 char encodingBuffer[buffersize];
291 if (!encodeValue(_value, encodingBuffer, buffersize)) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100292 vlog.error(_("The parameter %s was too large to write to the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000293 return;
294 }
295
296 wchar_t value[buffersize];
297 size = fl_utf8towc(encodingBuffer, strlen(encodingBuffer)+1, value, buffersize);
298 if (size >= buffersize) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100299 vlog.error(_("The parameter %s was too large to write to the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000300 return;
301 }
302
303 LONG res = RegSetValueExW(*hKey, name, 0, REG_SZ, (BYTE*)&value, (wcslen(value)+1)*2);
304 if (res != ERROR_SUCCESS) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100305 vlog.error(_("Failed to write parameter %s of type %s to the registry: %ld"),
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100306 _name, "REG_SZ", res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000307 return;
308 }
309}
310
311
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100312static void setKeyInt(const char *_name, const int _value, HKEY* hKey) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000313
314 const DWORD buffersize = 256;
315 wchar_t name[buffersize];
316 DWORD value = _value;
317
318 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
319 if (size >= buffersize) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100320 vlog.error(_("The name of the parameter %s was too large to write to the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000321 return;
322 }
323
324 LONG res = RegSetValueExW(*hKey, name, 0, REG_DWORD, (BYTE*)&value, sizeof(DWORD));
325 if (res != ERROR_SUCCESS) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100326 vlog.error(_("Failed to write parameter %s of type %s to the registry: %ld"),
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100327 _name, "REG_DWORD", res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000328 return;
329 }
330}
331
332
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100333static bool getKeyString(const char* _name, char* dest, size_t destSize, HKEY* hKey) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000334
335 DWORD buffersize = 256;
336 WCHAR value[destSize];
337 wchar_t name[buffersize];
338
339 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
340 if (size >= buffersize) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100341 vlog.error(_("The name of the parameter %s was too large to read from the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000342 return false;
343 }
344
345 LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)value, &buffersize);
346 if (res != ERROR_SUCCESS){
347 if (res == ERROR_FILE_NOT_FOUND) {
348 // The value does not exist, defaults will be used.
349 } else {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100350 vlog.error(_("Failed to read parameter %s from the registry: %ld"),
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100351 _name, res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000352 }
353 return false;
354 }
355
356 char utf8val[destSize];
357 size = fl_utf8fromwc(utf8val, sizeof(utf8val), value, wcslen(value)+1);
358 if (size >= sizeof(utf8val)) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100359 vlog.error(_("The parameter %s was too large to read from the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000360 return false;
361 }
362 const char *ret = utf8val;
363
364 if(decodeValue(ret, dest, destSize))
365 return true;
366 else
367 return false;
368}
369
370
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100371static bool getKeyInt(const char* _name, int* dest, HKEY* hKey) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000372
373 const DWORD buffersize = 256;
374 DWORD dwordsize = sizeof(DWORD);
375 DWORD value = 0;
376 wchar_t name[buffersize];
377
378 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
379 if (size >= buffersize) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100380 vlog.error(_("The name of the parameter %s was too large to read from the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000381 return false;
382 }
383
384 LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)&value, &dwordsize);
385 if (res != ERROR_SUCCESS){
386 if (res == ERROR_FILE_NOT_FOUND) {
387 // The value does not exist, defaults will be used.
388 } else {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100389 vlog.error(_("Failed to read parameter %s from the registry: %ld"),
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100390 _name, res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000391 }
392 return false;
393 }
394
395 *dest = (int)value;
396 return true;
397}
398
399
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100400static void saveToReg(const char* servername) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000401
402 HKEY hKey;
403
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200404 LONG res = RegCreateKeyExW(HKEY_CURRENT_USER,
405 L"Software\\TigerVNC\\vncviewer", 0, NULL,
406 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
407 &hKey, NULL);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000408 if (res != ERROR_SUCCESS) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100409 vlog.error(_("Failed to create registry key: %ld"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000410 return;
411 }
412
413 setKeyString("ServerName", servername, &hKey);
414
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100415 for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000416 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
417 setKeyString(parameterArray[i]->getName(), *(StringParameter*)parameterArray[i], &hKey);
418 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
419 setKeyInt(parameterArray[i]->getName(), (int)*(IntParameter*)parameterArray[i], &hKey);
420 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
421 setKeyInt(parameterArray[i]->getName(), (int)*(BoolParameter*)parameterArray[i], &hKey);
422 } else {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100423 vlog.error(_("Unknown parameter type for parameter %s"),
424 parameterArray[i]->getName());
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000425 }
426 }
427
428 res = RegCloseKey(hKey);
429 if (res != ERROR_SUCCESS) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100430 vlog.error(_("Failed to close registry key: %ld"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000431 }
432}
433
434
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100435static char* loadFromReg() {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000436
437 HKEY hKey;
438
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200439 LONG res = RegOpenKeyExW(HKEY_CURRENT_USER,
440 L"Software\\TigerVNC\\vncviewer", 0,
441 KEY_READ, &hKey);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000442 if (res != ERROR_SUCCESS) {
443 if (res == ERROR_FILE_NOT_FOUND) {
444 // The key does not exist, defaults will be used.
445 } else {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100446 vlog.error(_("Failed to open registry key: %ld"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000447 }
448 return NULL;
449 }
450
451 const size_t buffersize = 256;
452 static char servername[buffersize];
453
454 char servernameBuffer[buffersize];
455 if (getKeyString("ServerName", servernameBuffer, buffersize, &hKey))
456 snprintf(servername, buffersize, "%s", servernameBuffer);
457
458 int intValue = 0;
459 char stringValue[buffersize];
460
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100461 for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000462 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
463 if (getKeyString(parameterArray[i]->getName(), stringValue, buffersize, &hKey))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200464 parameterArray[i]->setParam(stringValue);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000465 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
466 if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200467 ((IntParameter*)parameterArray[i])->setParam(intValue);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000468 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
469 if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200470 ((BoolParameter*)parameterArray[i])->setParam(intValue);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000471 } else {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100472 vlog.error(_("Unknown parameter type for parameter %s"),
473 parameterArray[i]->getName());
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000474 }
475 }
476
477 res = RegCloseKey(hKey);
478 if (res != ERROR_SUCCESS){
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100479 vlog.error(_("Failed to close registry key: %ld"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000480 }
481
482 return servername;
483}
484#endif // _WIN32
485
486
487void saveViewerParameters(const char *filename, const char *servername) {
488
489 const size_t buffersize = 256;
490 char filepath[PATH_MAX];
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000491 char encodingBuffer[buffersize];
492
493 // Write to the registry or a predefined file if no filename was specified.
494 if(filename == NULL) {
495
496#ifdef _WIN32
497 saveToReg(servername);
498 return;
499#endif
500
501 char* homeDir = NULL;
502 if (getvnchomedir(&homeDir) == -1) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200503 vlog.error(_("Failed to write configuration file, can't obtain home "
504 "directory path."));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000505 return;
506 }
507
508 snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
509 } else {
510 snprintf(filepath, sizeof(filepath), "%s", filename);
511 }
512
513 /* Write parameters to file */
514 FILE* f = fopen(filepath, "w+");
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100515 if (!f)
516 throw Exception(_("Failed to write configuration file, can't open %s: %s"),
517 filepath, strerror(errno));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000518
519 fprintf(f, "%s\r\n", IDENTIFIER_STRING);
520 fprintf(f, "\r\n");
521
522 if (encodeValue(servername, encodingBuffer, buffersize))
523 fprintf(f, "ServerName=%s\n", encodingBuffer);
524
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100525 for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000526 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
527 if (encodeValue(*(StringParameter*)parameterArray[i], encodingBuffer, buffersize))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200528 fprintf(f, "%s=%s\n", ((StringParameter*)parameterArray[i])->getName(), encodingBuffer);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000529 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
530 fprintf(f, "%s=%d\n", ((IntParameter*)parameterArray[i])->getName(), (int)*(IntParameter*)parameterArray[i]);
531 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
532 fprintf(f, "%s=%d\n", ((BoolParameter*)parameterArray[i])->getName(), (int)*(BoolParameter*)parameterArray[i]);
533 } else {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100534 vlog.error(_("Unknown parameter type for parameter %s"),
535 parameterArray[i]->getName());
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000536 }
537 }
538 fclose(f);
539}
540
541
542char* loadViewerParameters(const char *filename) {
543
544 const size_t buffersize = 256;
545 char filepath[PATH_MAX];
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000546 char line[buffersize];
547 char decodingBuffer[buffersize];
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000548 static char servername[sizeof(line)];
549
550 // Load from the registry or a predefined file if no filename was specified.
551 if(filename == NULL) {
552
553#ifdef _WIN32
554 return loadFromReg();
555#endif
556
557 char* homeDir = NULL;
558 if (getvnchomedir(&homeDir) == -1)
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200559 throw Exception(_("Failed to read configuration file, "
560 "can't obtain home directory path."));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000561
562 snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
563 } else {
564 snprintf(filepath, sizeof(filepath), "%s", filename);
565 }
566
567 /* Read parameters from file */
568 FILE* f = fopen(filepath, "r");
569 if (!f) {
570 if (!filename)
571 return NULL; // Use defaults.
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100572 throw Exception(_("Failed to read configuration file, can't open %s: %s"),
573 filepath, strerror(errno));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000574 }
575
576 int lineNr = 0;
577 while (!feof(f)) {
578
579 // Read the next line
580 lineNr++;
581 if (!fgets(line, sizeof(line), f)) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000582 if (feof(f))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200583 break;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000584
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100585 throw Exception(_("Failed to read line %d in file %s: %s"),
586 lineNr, filepath, strerror(errno));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000587 }
Pierre Ossman3b865f12015-03-04 09:53:16 +0100588
589 if (strlen(line) == (sizeof(line) - 1))
590 throw Exception(_("Failed to read line %d in file %s: %s"),
591 lineNr, filepath, _("Line too long"));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000592
593 // Make sure that the first line of the file has the file identifier string
594 if(lineNr == 1) {
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100595 if(strncmp(line, IDENTIFIER_STRING, strlen(IDENTIFIER_STRING)) == 0)
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200596 continue;
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100597 else
598 throw Exception(_("Configuration file %s is in an invalid format"),
599 filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000600 }
601
602 // Skip empty lines and comments
603 if ((line[0] == '\n') || (line[0] == '#') || (line[0] == '\r'))
604 continue;
605
606 int len = strlen(line);
607 if (line[len-1] == '\n') {
608 line[len-1] = '\0';
609 len--;
610 }
611
612 // Find the parameter value
613 char *value = strchr(line, '=');
614 if (value == NULL) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100615 vlog.error(_("Failed to read line %d in file %s: %s"),
616 lineNr, filepath, _("Invalid format"));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000617 continue;
618 }
619 *value = '\0'; // line only contains the parameter name below.
620 value++;
621
622 bool invalidParameterName = true; // Will be set to false below if
623 // the line contains a valid name.
624
625 if (strcasecmp(line, "ServerName") == 0) {
626
627 if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100628 vlog.error(_("Failed to read line %d in file %s: %s"),
629 lineNr, filepath, _("Invalid format or too large value"));
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200630 continue;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000631 }
632 snprintf(servername, sizeof(decodingBuffer), "%s", decodingBuffer);
633 invalidParameterName = false;
634
635 } else {
636
637 // Find and set the correct parameter
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100638 for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000639
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200640 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
641 if (strcasecmp(line, ((StringParameter*)parameterArray[i])->getName()) == 0) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000642
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200643 if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100644 vlog.error(_("Failed to read line %d in file %s: %s"),
645 lineNr, filepath, _("Invalid format or too large value"));
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200646 continue;
647 }
648 ((StringParameter*)parameterArray[i])->setParam(decodingBuffer);
649 invalidParameterName = false;
650 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000651
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200652 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
653 if (strcasecmp(line, ((IntParameter*)parameterArray[i])->getName()) == 0) {
654 ((IntParameter*)parameterArray[i])->setParam(atoi(value));
655 invalidParameterName = false;
656 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000657
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200658 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
659 if (strcasecmp(line, ((BoolParameter*)parameterArray[i])->getName()) == 0) {
660 ((BoolParameter*)parameterArray[i])->setParam(atoi(value));
661 invalidParameterName = false;
662 }
663
664 } else {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100665 vlog.error(_("Unknown parameter type for parameter %s"),
666 parameterArray[i]->getName());
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200667 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000668 }
669 }
670
671 if (invalidParameterName)
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100672 vlog.info(_("Unknown parameter %s on line %d in file %s"),
673 line, lineNr, filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000674 }
675 fclose(f); f=0;
676
677 return servername;
678}