blob: 7a868c7cdb9481717676d73f6b4f94049764dbdb [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 Ossman2441e822012-07-10 11:11:23 +000095#ifdef HAVE_FLTK_FULLSCREEN
Pierre Ossman5156d5e2011-03-09 09:42:34 +000096BoolParameter fullScreen("FullScreen", "Full screen mode", false);
Pierre Ossmanaae38912012-07-13 11:22:55 +000097#ifdef HAVE_FLTK_FULLSCREEN_SCREENS
98BoolParameter fullScreenAllMonitors("FullScreenAllMonitors",
99 "Enable full screen over all monitors",
100 true);
101#endif // HAVE_FLTK_FULLSCREEN_SCREENS
Pierre Ossman2441e822012-07-10 11:11:23 +0000102#endif // HAVE_FLTK_FULLSCREEN
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000103StringParameter desktopSize("DesktopSize",
104 "Reconfigure desktop size on the server on "
105 "connect (if possible)", "");
Peter Åstrandb182a9e2012-08-27 07:28:08 +0000106StringParameter geometry("geometry",
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200107 "Specify size and position of viewer window", "");
Pierre Ossman2a7a8d62013-02-15 08:33:39 +0000108
109BoolParameter listenMode("listen", "Listen for connections from VNC servers", false);
110
Pierre Ossmanff473402012-07-04 11:27:47 +0000111BoolParameter remoteResize("RemoteResize",
112 "Dynamically resize the remote desktop size as "
113 "the size of the local client window changes. "
114 "(Does not work with all servers)", true);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000115
116BoolParameter viewOnly("ViewOnly",
117 "Don't send any mouse or keyboard events to the server",
118 false);
119BoolParameter shared("Shared",
120 "Don't disconnect other viewers upon connection - "
121 "share the desktop instead",
122 false);
123
124BoolParameter acceptClipboard("AcceptClipboard",
125 "Accept clipboard changes from the server",
126 true);
127BoolParameter sendClipboard("SendClipboard",
128 "Send clipboard changes to the server", true);
129BoolParameter sendPrimary("SendPrimary",
130 "Send the primary selection and cut buffer to the "
131 "server as well as the clipboard selection",
132 true);
133
134StringParameter menuKey("MenuKey", "The key which brings up the popup menu",
135 "F8");
136
Pierre Ossman407a5c32011-05-26 14:48:29 +0000137BoolParameter fullscreenSystemKeys("FullscreenSystemKeys",
138 "Pass special keys (like Alt+Tab) directly "
139 "to the server when in full screen mode.",
140 true);
141
Adam Tkac8ac4b302013-01-23 13:55:46 +0000142#ifndef WIN32
143StringParameter via("via", "Gateway to tunnel via", "");
144#endif
145
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100146static const char* IDENTIFIER_STRING = "TigerVNC Configuration file Version 1.0";
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000147
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100148static VoidParameter* parameterArray[] = {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000149#ifdef HAVE_GNUTLS
Pierre Ossman3d2a84b2014-09-17 16:45:35 +0200150 &CSecurityTLS::X509CA,
151 &CSecurityTLS::X509CRL,
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000152#endif // HAVE_GNUTLS
153 &SecurityClient::secTypes,
154 &dotWhenNoCursor,
155 &autoSelect,
156 &fullColour,
157 &lowColourLevel,
158 &preferredEncoding,
159 &customCompressLevel,
160 &compressLevel,
161 &noJpeg,
162 &qualityLevel,
163#ifdef HAVE_FLTK_FULLSCREEN
164 &fullScreen,
165#ifdef HAVE_FLTK_FULLSCREEN_SCREENS
166 &fullScreenAllMonitors,
167#endif // HAVE_FLTK_FULLSCREEN_SCREENS
168#endif // HAVE_FLTK_FULLSCREEN
169 &desktopSize,
Peter Åstrandb182a9e2012-08-27 07:28:08 +0000170 &geometry,
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000171 &remoteResize,
172 &viewOnly,
173 &shared,
174 &acceptClipboard,
175 &sendClipboard,
176 &sendPrimary,
177 &menuKey,
178 &fullscreenSystemKeys
179};
180
181// Encoding Table
182static struct {
183 const char first;
184 const char second;
Pierre Ossman6e538b42015-03-03 16:48:01 +0100185} replaceMap[] = { { '\n', 'n' },
186 { '\r', 'r' } };
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000187
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100188static bool encodeValue(const char* val, char* dest, size_t destSize) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000189
190 bool normalCharacter = true;
191 size_t pos = 0;
192
193 for (int i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) {
194
195 // Check for sequences which will need encoding
196 if (val[i] == '\\') {
197
198 strncpy(dest+pos, "\\\\", 2);
199 pos++;
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100200 if (pos >= destSize)
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200201 return false;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000202
203 } else {
204
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100205 for (size_t j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000206
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200207 if (val[i] == replaceMap[j].first) {
208 dest[pos] = '\\';
209 pos++;
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100210 if (pos >= destSize)
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200211 return false;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000212
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200213 dest[pos] = replaceMap[j].second;
214 normalCharacter = false;
215 break;
216 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000217
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200218 if (normalCharacter) {
219 dest[pos] = val[i];
220 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000221 }
222 }
223 normalCharacter = true; // Reset for next loop
224
225 pos++;
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100226 if (pos >= destSize)
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000227 return false;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000228 }
229
230 dest[pos] = '\0';
231 return true;
232}
233
234
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100235static bool decodeValue(const char* val, char* dest, size_t destSize) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000236
237 size_t pos = 0;
238 bool escapedCharacter = false;
239
240 for (int i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) {
241
242 // Check for escape sequences
243 if (val[i] == '\\') {
244
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100245 for (size_t j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) {
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200246 if (val[i+1] == replaceMap[j].second) {
247 dest[pos] = replaceMap[j].first;
248 escapedCharacter = true;
249 pos--;
250 break;
251 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000252 }
253
254 if (!escapedCharacter) {
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200255 if (val[i+1] == '\\') {
256 dest[pos] = val[i];
257 i++;
258 } else {
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200259 return false;
260 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000261 }
262
263 } else {
264 dest[pos] = val[i];
265 }
266
267 escapedCharacter = false; // Reset for next loop
268 pos++;
269 if (pos >= destSize) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000270 return false;
271 }
272 }
273
274 dest[pos] = '\0';
275 return true;
276}
277
278
279#ifdef _WIN32
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100280static void setKeyString(const char *_name, const char *_value, HKEY* hKey) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000281
282 const DWORD buffersize = 256;
283
284 wchar_t name[buffersize];
285 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
286 if (size >= buffersize) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100287 vlog.error(_("The name of the parameter %s was too large to write to the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000288 return;
289 }
290
291 char encodingBuffer[buffersize];
292 if (!encodeValue(_value, encodingBuffer, buffersize)) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100293 vlog.error(_("The parameter %s was too large to write to the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000294 return;
295 }
296
297 wchar_t value[buffersize];
298 size = fl_utf8towc(encodingBuffer, strlen(encodingBuffer)+1, value, buffersize);
299 if (size >= buffersize) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100300 vlog.error(_("The parameter %s was too large to write to the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000301 return;
302 }
303
304 LONG res = RegSetValueExW(*hKey, name, 0, REG_SZ, (BYTE*)&value, (wcslen(value)+1)*2);
305 if (res != ERROR_SUCCESS) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100306 vlog.error(_("Failed to write parameter %s of type %s to the registry: %ld"),
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100307 _name, "REG_SZ", res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000308 return;
309 }
310}
311
312
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100313static void setKeyInt(const char *_name, const int _value, HKEY* hKey) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000314
315 const DWORD buffersize = 256;
316 wchar_t name[buffersize];
317 DWORD value = _value;
318
319 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
320 if (size >= buffersize) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100321 vlog.error(_("The name of the parameter %s was too large to write to the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000322 return;
323 }
324
325 LONG res = RegSetValueExW(*hKey, name, 0, REG_DWORD, (BYTE*)&value, sizeof(DWORD));
326 if (res != ERROR_SUCCESS) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100327 vlog.error(_("Failed to write parameter %s of type %s to the registry: %ld"),
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100328 _name, "REG_DWORD", res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000329 return;
330 }
331}
332
333
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100334static bool getKeyString(const char* _name, char* dest, size_t destSize, HKEY* hKey) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000335
336 DWORD buffersize = 256;
337 WCHAR value[destSize];
338 wchar_t name[buffersize];
339
340 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
341 if (size >= buffersize) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100342 vlog.error(_("The name of the parameter %s was too large to read from the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000343 return false;
344 }
345
346 LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)value, &buffersize);
347 if (res != ERROR_SUCCESS){
348 if (res == ERROR_FILE_NOT_FOUND) {
349 // The value does not exist, defaults will be used.
350 } else {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100351 vlog.error(_("Failed to read parameter %s from the registry: %ld"),
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100352 _name, res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000353 }
354 return false;
355 }
356
357 char utf8val[destSize];
358 size = fl_utf8fromwc(utf8val, sizeof(utf8val), value, wcslen(value)+1);
359 if (size >= sizeof(utf8val)) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100360 vlog.error(_("The parameter %s was too large to read from the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000361 return false;
362 }
363 const char *ret = utf8val;
364
365 if(decodeValue(ret, dest, destSize))
366 return true;
367 else
368 return false;
369}
370
371
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100372static bool getKeyInt(const char* _name, int* dest, HKEY* hKey) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000373
374 const DWORD buffersize = 256;
375 DWORD dwordsize = sizeof(DWORD);
376 DWORD value = 0;
377 wchar_t name[buffersize];
378
379 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
380 if (size >= buffersize) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100381 vlog.error(_("The name of the parameter %s was too large to read from the registry"), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000382 return false;
383 }
384
385 LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)&value, &dwordsize);
386 if (res != ERROR_SUCCESS){
387 if (res == ERROR_FILE_NOT_FOUND) {
388 // The value does not exist, defaults will be used.
389 } else {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100390 vlog.error(_("Failed to read parameter %s from the registry: %ld"),
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100391 _name, res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000392 }
393 return false;
394 }
395
396 *dest = (int)value;
397 return true;
398}
399
400
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100401static void saveToReg(const char* servername) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000402
403 HKEY hKey;
404
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200405 LONG res = RegCreateKeyExW(HKEY_CURRENT_USER,
406 L"Software\\TigerVNC\\vncviewer", 0, NULL,
407 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
408 &hKey, NULL);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000409 if (res != ERROR_SUCCESS) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100410 vlog.error(_("Failed to create registry key: %ld"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000411 return;
412 }
413
414 setKeyString("ServerName", servername, &hKey);
415
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100416 for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000417 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
418 setKeyString(parameterArray[i]->getName(), *(StringParameter*)parameterArray[i], &hKey);
419 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
420 setKeyInt(parameterArray[i]->getName(), (int)*(IntParameter*)parameterArray[i], &hKey);
421 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
422 setKeyInt(parameterArray[i]->getName(), (int)*(BoolParameter*)parameterArray[i], &hKey);
423 } else {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100424 vlog.error(_("Unknown parameter type for parameter %s"),
425 parameterArray[i]->getName());
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000426 }
427 }
428
429 res = RegCloseKey(hKey);
430 if (res != ERROR_SUCCESS) {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100431 vlog.error(_("Failed to close registry key: %ld"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000432 }
433}
434
435
Pierre Ossmanc0ea6422014-12-03 14:04:11 +0100436static char* loadFromReg() {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000437
438 HKEY hKey;
439
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200440 LONG res = RegOpenKeyExW(HKEY_CURRENT_USER,
441 L"Software\\TigerVNC\\vncviewer", 0,
442 KEY_READ, &hKey);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000443 if (res != ERROR_SUCCESS) {
444 if (res == ERROR_FILE_NOT_FOUND) {
445 // The key does not exist, defaults will be used.
446 } else {
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100447 vlog.error(_("Failed to open registry key: %ld"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000448 }
449 return NULL;
450 }
451
452 const size_t buffersize = 256;
453 static char servername[buffersize];
454
455 char servernameBuffer[buffersize];
456 if (getKeyString("ServerName", servernameBuffer, buffersize, &hKey))
457 snprintf(servername, buffersize, "%s", servernameBuffer);
458
459 int intValue = 0;
460 char stringValue[buffersize];
461
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100462 for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000463 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
464 if (getKeyString(parameterArray[i]->getName(), stringValue, buffersize, &hKey))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200465 parameterArray[i]->setParam(stringValue);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000466 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
467 if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200468 ((IntParameter*)parameterArray[i])->setParam(intValue);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000469 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
470 if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200471 ((BoolParameter*)parameterArray[i])->setParam(intValue);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000472 } else {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100473 vlog.error(_("Unknown parameter type for parameter %s"),
474 parameterArray[i]->getName());
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000475 }
476 }
477
478 res = RegCloseKey(hKey);
479 if (res != ERROR_SUCCESS){
Pierre Ossmanfb450fb2015-03-03 16:34:56 +0100480 vlog.error(_("Failed to close registry key: %ld"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000481 }
482
483 return servername;
484}
485#endif // _WIN32
486
487
488void saveViewerParameters(const char *filename, const char *servername) {
489
490 const size_t buffersize = 256;
491 char filepath[PATH_MAX];
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000492 char encodingBuffer[buffersize];
493
494 // Write to the registry or a predefined file if no filename was specified.
495 if(filename == NULL) {
496
497#ifdef _WIN32
498 saveToReg(servername);
499 return;
500#endif
501
502 char* homeDir = NULL;
503 if (getvnchomedir(&homeDir) == -1) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200504 vlog.error(_("Failed to write configuration file, can't obtain home "
505 "directory path."));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000506 return;
507 }
508
509 snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
510 } else {
511 snprintf(filepath, sizeof(filepath), "%s", filename);
512 }
513
514 /* Write parameters to file */
515 FILE* f = fopen(filepath, "w+");
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100516 if (!f)
517 throw Exception(_("Failed to write configuration file, can't open %s: %s"),
518 filepath, strerror(errno));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000519
520 fprintf(f, "%s\r\n", IDENTIFIER_STRING);
521 fprintf(f, "\r\n");
522
523 if (encodeValue(servername, encodingBuffer, buffersize))
524 fprintf(f, "ServerName=%s\n", encodingBuffer);
525
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100526 for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000527 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
528 if (encodeValue(*(StringParameter*)parameterArray[i], encodingBuffer, buffersize))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200529 fprintf(f, "%s=%s\n", ((StringParameter*)parameterArray[i])->getName(), encodingBuffer);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000530 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
531 fprintf(f, "%s=%d\n", ((IntParameter*)parameterArray[i])->getName(), (int)*(IntParameter*)parameterArray[i]);
532 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
533 fprintf(f, "%s=%d\n", ((BoolParameter*)parameterArray[i])->getName(), (int)*(BoolParameter*)parameterArray[i]);
534 } else {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100535 vlog.error(_("Unknown parameter type for parameter %s"),
536 parameterArray[i]->getName());
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000537 }
538 }
539 fclose(f);
540}
541
542
543char* loadViewerParameters(const char *filename) {
544
545 const size_t buffersize = 256;
546 char filepath[PATH_MAX];
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000547 char line[buffersize];
548 char decodingBuffer[buffersize];
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000549 static char servername[sizeof(line)];
550
551 // Load from the registry or a predefined file if no filename was specified.
552 if(filename == NULL) {
553
554#ifdef _WIN32
555 return loadFromReg();
556#endif
557
558 char* homeDir = NULL;
559 if (getvnchomedir(&homeDir) == -1)
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200560 throw Exception(_("Failed to read configuration file, "
561 "can't obtain home directory path."));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000562
563 snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
564 } else {
565 snprintf(filepath, sizeof(filepath), "%s", filename);
566 }
567
568 /* Read parameters from file */
569 FILE* f = fopen(filepath, "r");
570 if (!f) {
571 if (!filename)
572 return NULL; // Use defaults.
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100573 throw Exception(_("Failed to read configuration file, can't open %s: %s"),
574 filepath, strerror(errno));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000575 }
576
577 int lineNr = 0;
578 while (!feof(f)) {
579
580 // Read the next line
581 lineNr++;
582 if (!fgets(line, sizeof(line), f)) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000583 if (feof(f))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200584 break;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000585
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100586 throw Exception(_("Failed to read line %d in file %s: %s"),
587 lineNr, filepath, strerror(errno));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000588 }
Pierre Ossman3b865f12015-03-04 09:53:16 +0100589
590 if (strlen(line) == (sizeof(line) - 1))
591 throw Exception(_("Failed to read line %d in file %s: %s"),
592 lineNr, filepath, _("Line too long"));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000593
594 // Make sure that the first line of the file has the file identifier string
595 if(lineNr == 1) {
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100596 if(strncmp(line, IDENTIFIER_STRING, strlen(IDENTIFIER_STRING)) == 0)
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200597 continue;
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100598 else
599 throw Exception(_("Configuration file %s is in an invalid format"),
600 filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000601 }
602
603 // Skip empty lines and comments
604 if ((line[0] == '\n') || (line[0] == '#') || (line[0] == '\r'))
605 continue;
606
607 int len = strlen(line);
608 if (line[len-1] == '\n') {
609 line[len-1] = '\0';
610 len--;
611 }
612
613 // Find the parameter value
614 char *value = strchr(line, '=');
615 if (value == NULL) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100616 vlog.error(_("Failed to read line %d in file %s: %s"),
617 lineNr, filepath, _("Invalid format"));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000618 continue;
619 }
620 *value = '\0'; // line only contains the parameter name below.
621 value++;
622
623 bool invalidParameterName = true; // Will be set to false below if
624 // the line contains a valid name.
625
626 if (strcasecmp(line, "ServerName") == 0) {
627
628 if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100629 vlog.error(_("Failed to read line %d in file %s: %s"),
630 lineNr, filepath, _("Invalid format or too large value"));
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200631 continue;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000632 }
633 snprintf(servername, sizeof(decodingBuffer), "%s", decodingBuffer);
634 invalidParameterName = false;
635
636 } else {
637
638 // Find and set the correct parameter
Pierre Ossman5c23b9e2015-03-03 16:26:03 +0100639 for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000640
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200641 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
642 if (strcasecmp(line, ((StringParameter*)parameterArray[i])->getName()) == 0) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000643
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200644 if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100645 vlog.error(_("Failed to read line %d in file %s: %s"),
646 lineNr, filepath, _("Invalid format or too large value"));
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200647 continue;
648 }
649 ((StringParameter*)parameterArray[i])->setParam(decodingBuffer);
650 invalidParameterName = false;
651 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000652
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200653 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
654 if (strcasecmp(line, ((IntParameter*)parameterArray[i])->getName()) == 0) {
655 ((IntParameter*)parameterArray[i])->setParam(atoi(value));
656 invalidParameterName = false;
657 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000658
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200659 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
660 if (strcasecmp(line, ((BoolParameter*)parameterArray[i])->getName()) == 0) {
661 ((BoolParameter*)parameterArray[i])->setParam(atoi(value));
662 invalidParameterName = false;
663 }
664
665 } else {
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100666 vlog.error(_("Unknown parameter type for parameter %s"),
667 parameterArray[i]->getName());
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200668 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000669 }
670 }
671
672 if (invalidParameterName)
Pierre Ossman1bfbcb52014-12-03 14:03:29 +0100673 vlog.info(_("Unknown parameter %s on line %d in file %s"),
674 line, lineNr, filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000675 }
676 fclose(f); f=0;
677
678 return servername;
679}