blob: 9a1648132f3c851d15d17bb73ed2224e0ebc3980 [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>
46
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +020047#include "i18n.h"
48
Pierre Ossman5156d5e2011-03-09 09:42:34 +000049using namespace rfb;
50
Peter Åstrand8a2b0812012-08-08 11:49:01 +000051static LogWriter vlog("Parameters");
52
53
Pierre Ossman4c8e3112011-06-08 17:21:48 +000054IntParameter pointerEventInterval("PointerEventInterval",
55 "Time in milliseconds to rate-limit"
56 " successive pointer events", 0);
Pierre Ossman5156d5e2011-03-09 09:42:34 +000057BoolParameter dotWhenNoCursor("DotWhenNoCursor",
58 "Show the dot cursor when the server sends an "
Pierre Ossman93f37742011-06-09 08:35:34 +000059 "invisible cursor", false);
Pierre Ossman5156d5e2011-03-09 09:42:34 +000060
61StringParameter passwordFile("PasswordFile",
62 "Password file for VNC authentication", "");
63AliasParameter passwd("passwd", "Alias for PasswordFile", &passwordFile);
64
65BoolParameter autoSelect("AutoSelect",
66 "Auto select pixel format and encoding. "
67 "Default if PreferredEncoding and FullColor are not specified.",
68 true);
69BoolParameter fullColour("FullColor",
70 "Use full color", true);
71AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
72IntParameter lowColourLevel("LowColorLevel",
73 "Color level to use on slow connections. "
74 "0 = Very Low (8 colors), 1 = Low (64 colors), "
75 "2 = Medium (256 colors)", 2);
76AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
77StringParameter preferredEncoding("PreferredEncoding",
78 "Preferred encoding to use (Tight, ZRLE, Hextile or"
79 " Raw)", "Tight");
80BoolParameter customCompressLevel("CustomCompressLevel",
81 "Use custom compression level. "
82 "Default if CompressLevel is specified.", false);
83IntParameter compressLevel("CompressLevel",
DRCba7bc512011-08-17 02:30:34 +000084 "Use specified compression level 0 = Low, 6 = High",
Pierre Ossman701ad682011-11-20 15:39:17 +000085 2);
Pierre Ossman5156d5e2011-03-09 09:42:34 +000086BoolParameter noJpeg("NoJPEG",
87 "Disable lossy JPEG compression in Tight encoding.",
88 false);
89IntParameter qualityLevel("QualityLevel",
90 "JPEG quality level. 0 = Low, 9 = High",
91 8);
92
Peter Åstrand49b11572012-08-01 08:09:09 +000093BoolParameter maximize("Maximize", "Maximize viewer window", false);
Pierre Ossman2441e822012-07-10 11:11:23 +000094#ifdef HAVE_FLTK_FULLSCREEN
Pierre Ossman5156d5e2011-03-09 09:42:34 +000095BoolParameter fullScreen("FullScreen", "Full screen mode", false);
Pierre Ossmanaae38912012-07-13 11:22:55 +000096#ifdef HAVE_FLTK_FULLSCREEN_SCREENS
97BoolParameter fullScreenAllMonitors("FullScreenAllMonitors",
98 "Enable full screen over all monitors",
99 true);
100#endif // HAVE_FLTK_FULLSCREEN_SCREENS
Pierre Ossman2441e822012-07-10 11:11:23 +0000101#endif // HAVE_FLTK_FULLSCREEN
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000102StringParameter desktopSize("DesktopSize",
103 "Reconfigure desktop size on the server on "
104 "connect (if possible)", "");
Peter Åstrandb182a9e2012-08-27 07:28:08 +0000105StringParameter geometry("geometry",
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200106 "Specify size and position of viewer window", "");
Pierre Ossman2a7a8d62013-02-15 08:33:39 +0000107
108BoolParameter listenMode("listen", "Listen for connections from VNC servers", false);
109
Pierre Ossmanff473402012-07-04 11:27:47 +0000110BoolParameter remoteResize("RemoteResize",
111 "Dynamically resize the remote desktop size as "
112 "the size of the local client window changes. "
113 "(Does not work with all servers)", true);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000114
115BoolParameter viewOnly("ViewOnly",
116 "Don't send any mouse or keyboard events to the server",
117 false);
118BoolParameter shared("Shared",
119 "Don't disconnect other viewers upon connection - "
120 "share the desktop instead",
121 false);
122
123BoolParameter acceptClipboard("AcceptClipboard",
124 "Accept clipboard changes from the server",
125 true);
126BoolParameter sendClipboard("SendClipboard",
127 "Send clipboard changes to the server", true);
128BoolParameter sendPrimary("SendPrimary",
129 "Send the primary selection and cut buffer to the "
130 "server as well as the clipboard selection",
131 true);
132
133StringParameter menuKey("MenuKey", "The key which brings up the popup menu",
134 "F8");
135
Pierre Ossman407a5c32011-05-26 14:48:29 +0000136BoolParameter fullscreenSystemKeys("FullscreenSystemKeys",
137 "Pass special keys (like Alt+Tab) directly "
138 "to the server when in full screen mode.",
139 true);
140
Adam Tkac8ac4b302013-01-23 13:55:46 +0000141#ifndef WIN32
142StringParameter via("via", "Gateway to tunnel via", "");
143#endif
144
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000145const char* IDENTIFIER_STRING = "TigerVNC Configuration file Version 1.0";
146
147VoidParameter* parameterArray[] = {
148#ifdef HAVE_GNUTLS
Pierre Ossman3d2a84b2014-09-17 16:45:35 +0200149 &CSecurityTLS::X509CA,
150 &CSecurityTLS::X509CRL,
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000151#endif // HAVE_GNUTLS
152 &SecurityClient::secTypes,
153 &dotWhenNoCursor,
154 &autoSelect,
155 &fullColour,
156 &lowColourLevel,
157 &preferredEncoding,
158 &customCompressLevel,
159 &compressLevel,
160 &noJpeg,
161 &qualityLevel,
162#ifdef HAVE_FLTK_FULLSCREEN
163 &fullScreen,
164#ifdef HAVE_FLTK_FULLSCREEN_SCREENS
165 &fullScreenAllMonitors,
166#endif // HAVE_FLTK_FULLSCREEN_SCREENS
167#endif // HAVE_FLTK_FULLSCREEN
168 &desktopSize,
Peter Åstrandb182a9e2012-08-27 07:28:08 +0000169 &geometry,
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000170 &remoteResize,
171 &viewOnly,
172 &shared,
173 &acceptClipboard,
174 &sendClipboard,
175 &sendPrimary,
176 &menuKey,
177 &fullscreenSystemKeys
178};
179
180// Encoding Table
181static struct {
182 const char first;
183 const char second;
184} replaceMap[] = {'\n', 'n',
185 '\r', 'r'};
186
187bool encodeValue(const char* val, char* dest, size_t destSize) {
188
189 bool normalCharacter = true;
190 size_t pos = 0;
191
192 for (int i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) {
193
194 // Check for sequences which will need encoding
195 if (val[i] == '\\') {
196
197 strncpy(dest+pos, "\\\\", 2);
198 pos++;
199 if (pos >= destSize) {
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200200 vlog.error(_("Encoding backslash: The size of the buffer dest "
201 "is to small, it needs to be more than %d bytes bigger."),
202 (destSize - 1 - i));
203 return false;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000204 }
205
206 } else {
207
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200208 for (int j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000209
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200210 if (val[i] == replaceMap[j].first) {
211 dest[pos] = '\\';
212 pos++;
213 if (pos >= destSize) {
214 vlog.error(_("Encoding escape sequence: The size of the buffer "
215 "dest is to small, it needs to be more than %d bytes "
216 "bigger."), (destSize - 1 - i));
217 return false;
218 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000219
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200220 dest[pos] = replaceMap[j].second;
221 normalCharacter = false;
222 break;
223 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000224
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200225 if (normalCharacter) {
226 dest[pos] = val[i];
227 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000228 }
229 }
230 normalCharacter = true; // Reset for next loop
231
232 pos++;
233 if (pos >= destSize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200234 vlog.error(_("Encoding normal character: The size of the buffer dest "
235 "is to small, it needs to be more than %d bytes bigger."),
236 (destSize - 1 - i));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000237 return false;
238 }
239
240 }
241
242 dest[pos] = '\0';
243 return true;
244}
245
246
247bool decodeValue(const char* val, char* dest, size_t destSize) {
248
249 size_t pos = 0;
250 bool escapedCharacter = false;
251
252 for (int i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) {
253
254 // Check for escape sequences
255 if (val[i] == '\\') {
256
257 for (int j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) {
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200258 if (val[i+1] == replaceMap[j].second) {
259 dest[pos] = replaceMap[j].first;
260 escapedCharacter = true;
261 pos--;
262 break;
263 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000264 }
265
266 if (!escapedCharacter) {
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200267 if (val[i+1] == '\\') {
268 dest[pos] = val[i];
269 i++;
270 } else {
271 vlog.error(_("Unknown escape sequence at character %d"), i);
272 return false;
273 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000274 }
275
276 } else {
277 dest[pos] = val[i];
278 }
279
280 escapedCharacter = false; // Reset for next loop
281 pos++;
282 if (pos >= destSize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200283 vlog.error(_("Decoding: The size of the buffer dest is to small, "
284 "it needs to be 1 byte bigger."));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000285 return false;
286 }
287 }
288
289 dest[pos] = '\0';
290 return true;
291}
292
293
294#ifdef _WIN32
295void setKeyString(const char *_name, const char *_value, HKEY* hKey) {
296
297 const DWORD buffersize = 256;
298
299 wchar_t name[buffersize];
300 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
301 if (size >= buffersize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200302 vlog.error(_("Could not convert the parameter-name %s to wchar_t* when "
303 "writing to the Registry, the buffersize is to small."),
304 _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000305 return;
306 }
307
308 char encodingBuffer[buffersize];
309 if (!encodeValue(_value, encodingBuffer, buffersize)) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200310 vlog.error(_("Could not encode the parameter-value %s when "
311 "writing to the Registry."), _value);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000312 return;
313 }
314
315 wchar_t value[buffersize];
316 size = fl_utf8towc(encodingBuffer, strlen(encodingBuffer)+1, value, buffersize);
317 if (size >= buffersize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200318 vlog.error(_("Could not convert the parameter-value %s to wchar_t* when "
319 "writing to the Registry, the buffersize is to small."),
320 _value);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000321 return;
322 }
323
324 LONG res = RegSetValueExW(*hKey, name, 0, REG_SZ, (BYTE*)&value, (wcslen(value)+1)*2);
325 if (res != ERROR_SUCCESS) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200326 vlog.error(_("Error(%d) writing %s(REG_SZ) to Registry."), res, _value);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000327 return;
328 }
329}
330
331
332void setKeyInt(const char *_name, const int _value, HKEY* hKey) {
333
334 const DWORD buffersize = 256;
335 wchar_t name[buffersize];
336 DWORD value = _value;
337
338 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
339 if (size >= buffersize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200340 vlog.error(_("Could not convert the parameter-name %s to wchar_t* when "
341 "writing to the Registry, the buffersize is to small."),
342 _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000343 return;
344 }
345
346 LONG res = RegSetValueExW(*hKey, name, 0, REG_DWORD, (BYTE*)&value, sizeof(DWORD));
347 if (res != ERROR_SUCCESS) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200348 vlog.error(_("Error(%d) writing %d(REG_DWORD) to Registry."), res, _value);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000349 return;
350 }
351}
352
353
354bool getKeyString(const char* _name, char* dest, size_t destSize, HKEY* hKey) {
355
356 DWORD buffersize = 256;
357 WCHAR value[destSize];
358 wchar_t name[buffersize];
359
360 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
361 if (size >= buffersize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200362 vlog.error(_("Could not convert the parameter-name %s to wchar_t* when "
363 "reading from the Registry, the buffersize is to small."),
364 _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000365 return false;
366 }
367
368 LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)value, &buffersize);
369 if (res != ERROR_SUCCESS){
370 if (res == ERROR_FILE_NOT_FOUND) {
371 // The value does not exist, defaults will be used.
372 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200373 vlog.error(_("Error(%d) reading %s from Registry."), res, _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000374 }
375 return false;
376 }
377
378 char utf8val[destSize];
379 size = fl_utf8fromwc(utf8val, sizeof(utf8val), value, wcslen(value)+1);
380 if (size >= sizeof(utf8val)) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200381 vlog.error(_("Could not convert the parameter-value for %s to utf8 "
382 "char* when reading from the Registry, the buffer dest is "
383 "to small."), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000384 return false;
385 }
386 const char *ret = utf8val;
387
388 if(decodeValue(ret, dest, destSize))
389 return true;
390 else
391 return false;
392}
393
394
395bool getKeyInt(const char* _name, int* dest, HKEY* hKey) {
396
397 const DWORD buffersize = 256;
398 DWORD dwordsize = sizeof(DWORD);
399 DWORD value = 0;
400 wchar_t name[buffersize];
401
402 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
403 if (size >= buffersize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200404 vlog.error(_("Could not convert the parameter-name %s to wchar_t* when "
405 "reading from the Registry, the buffersize is to small."),
406 _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000407 return false;
408 }
409
410 LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)&value, &dwordsize);
411 if (res != ERROR_SUCCESS){
412 if (res == ERROR_FILE_NOT_FOUND) {
413 // The value does not exist, defaults will be used.
414 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200415 vlog.error(_("Error(%d) reading %s from Registry."), res, _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000416 }
417 return false;
418 }
419
420 *dest = (int)value;
421 return true;
422}
423
424
425void saveToReg(const char* servername) {
426
427 HKEY hKey;
428
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200429 LONG res = RegCreateKeyExW(HKEY_CURRENT_USER,
430 L"Software\\TigerVNC\\vncviewer", 0, NULL,
431 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
432 &hKey, NULL);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000433 if (res != ERROR_SUCCESS) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200434 vlog.error(_("Error(%d) creating key: Software\\TigerVNC\\vncviewer"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000435 return;
436 }
437
438 setKeyString("ServerName", servername, &hKey);
439
440 for (int i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
441 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
442 setKeyString(parameterArray[i]->getName(), *(StringParameter*)parameterArray[i], &hKey);
443 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
444 setKeyInt(parameterArray[i]->getName(), (int)*(IntParameter*)parameterArray[i], &hKey);
445 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
446 setKeyInt(parameterArray[i]->getName(), (int)*(BoolParameter*)parameterArray[i], &hKey);
447 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200448 vlog.info(_("The parameterArray contains a object of a invalid type "
449 "at line %d."), i);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000450 }
451 }
452
453 res = RegCloseKey(hKey);
454 if (res != ERROR_SUCCESS) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200455 vlog.error(_("Error(%d) closing key: Software\\TigerVNC\\vncviewer"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000456 }
457}
458
459
460char* loadFromReg() {
461
462 HKEY hKey;
463
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200464 LONG res = RegOpenKeyExW(HKEY_CURRENT_USER,
465 L"Software\\TigerVNC\\vncviewer", 0,
466 KEY_READ, &hKey);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000467 if (res != ERROR_SUCCESS) {
468 if (res == ERROR_FILE_NOT_FOUND) {
469 // The key does not exist, defaults will be used.
470 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200471 vlog.error(_("Error(%d) opening key: Software\\TigerVNC\\vncviewer"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000472 }
473 return NULL;
474 }
475
476 const size_t buffersize = 256;
477 static char servername[buffersize];
478
479 char servernameBuffer[buffersize];
480 if (getKeyString("ServerName", servernameBuffer, buffersize, &hKey))
481 snprintf(servername, buffersize, "%s", servernameBuffer);
482
483 int intValue = 0;
484 char stringValue[buffersize];
485
486 for (int i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
487 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
488 if (getKeyString(parameterArray[i]->getName(), stringValue, buffersize, &hKey))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200489 parameterArray[i]->setParam(stringValue);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000490 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
491 if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200492 ((IntParameter*)parameterArray[i])->setParam(intValue);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000493 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
494 if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200495 ((BoolParameter*)parameterArray[i])->setParam(intValue);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000496 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200497 vlog.info(_("The parameterArray contains a object of a invalid type at line %d."), i);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000498 }
499 }
500
501 res = RegCloseKey(hKey);
502 if (res != ERROR_SUCCESS){
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200503 vlog.error(_("Error(%d) closing key: Software\\TigerVNC\\vncviewer"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000504 }
505
506 return servername;
507}
508#endif // _WIN32
509
510
511void saveViewerParameters(const char *filename, const char *servername) {
512
513 const size_t buffersize = 256;
514 char filepath[PATH_MAX];
515 char write_error[buffersize*2];
516 char encodingBuffer[buffersize];
517
518 // Write to the registry or a predefined file if no filename was specified.
519 if(filename == NULL) {
520
521#ifdef _WIN32
522 saveToReg(servername);
523 return;
524#endif
525
526 char* homeDir = NULL;
527 if (getvnchomedir(&homeDir) == -1) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200528 vlog.error(_("Failed to write configuration file, can't obtain home "
529 "directory path."));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000530 return;
531 }
532
533 snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
534 } else {
535 snprintf(filepath, sizeof(filepath), "%s", filename);
536 }
537
538 /* Write parameters to file */
539 FILE* f = fopen(filepath, "w+");
540 if (!f) {
Pierre Ossman74d412c2013-07-01 13:59:35 +0000541 snprintf(write_error, sizeof(write_error),
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200542 _("Failed to write configuration file, can't open %s"), filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000543 throw Exception(write_error);
544 }
545
546 fprintf(f, "%s\r\n", IDENTIFIER_STRING);
547 fprintf(f, "\r\n");
548
549 if (encodeValue(servername, encodingBuffer, buffersize))
550 fprintf(f, "ServerName=%s\n", encodingBuffer);
551
552 for (int i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
553 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
554 if (encodeValue(*(StringParameter*)parameterArray[i], encodingBuffer, buffersize))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200555 fprintf(f, "%s=%s\n", ((StringParameter*)parameterArray[i])->getName(), encodingBuffer);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000556 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
557 fprintf(f, "%s=%d\n", ((IntParameter*)parameterArray[i])->getName(), (int)*(IntParameter*)parameterArray[i]);
558 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
559 fprintf(f, "%s=%d\n", ((BoolParameter*)parameterArray[i])->getName(), (int)*(BoolParameter*)parameterArray[i]);
560 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200561 vlog.info(_("The parameterArray contains a object of a invalid type "
562 "at line %d."), i);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000563 }
564 }
565 fclose(f);
566}
567
568
569char* loadViewerParameters(const char *filename) {
570
571 const size_t buffersize = 256;
572 char filepath[PATH_MAX];
573 char readError[buffersize*2];
574 char line[buffersize];
575 char decodingBuffer[buffersize];
576 char decodedValue[buffersize];
577 static char servername[sizeof(line)];
578
579 // Load from the registry or a predefined file if no filename was specified.
580 if(filename == NULL) {
581
582#ifdef _WIN32
583 return loadFromReg();
584#endif
585
586 char* homeDir = NULL;
587 if (getvnchomedir(&homeDir) == -1)
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200588 throw Exception(_("Failed to read configuration file, "
589 "can't obtain home directory path."));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000590
591 snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
592 } else {
593 snprintf(filepath, sizeof(filepath), "%s", filename);
594 }
595
596 /* Read parameters from file */
597 FILE* f = fopen(filepath, "r");
598 if (!f) {
599 if (!filename)
600 return NULL; // Use defaults.
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200601 snprintf(readError, sizeof(readError),
602 _("Failed to read configuration file, can't open %s"), filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000603 throw Exception(readError);
604 }
605
606 int lineNr = 0;
607 while (!feof(f)) {
608
609 // Read the next line
610 lineNr++;
611 if (!fgets(line, sizeof(line), f)) {
612 if (line[sizeof(line) -1] != '\0') {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200613 vlog.error(_("Could not read the line(%d) in the configuration file,"
614 "the buffersize is to small."), lineNr);
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200615 return NULL;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000616 }
617 if (feof(f))
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200618 break;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000619
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200620 snprintf(readError, sizeof(readError),
621 _("Failed to read line %d in file %s"), lineNr, filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000622 throw Exception(readError);
623 }
624
625 // Make sure that the first line of the file has the file identifier string
626 if(lineNr == 1) {
627 if(strncmp(line, IDENTIFIER_STRING, strlen(IDENTIFIER_STRING)) == 0) {
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200628 continue;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000629 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200630 snprintf(readError, sizeof(readError),
631 _("Line 1 in file %s\nmust contain the TigerVNC "
632 "configuration file identifier string:\n"
633 "\"%s\""), filepath, IDENTIFIER_STRING);
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200634 throw Exception(readError);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000635 }
636 }
637
638 // Skip empty lines and comments
639 if ((line[0] == '\n') || (line[0] == '#') || (line[0] == '\r'))
640 continue;
641
642 int len = strlen(line);
643 if (line[len-1] == '\n') {
644 line[len-1] = '\0';
645 len--;
646 }
647
648 // Find the parameter value
649 char *value = strchr(line, '=');
650 if (value == NULL) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200651 vlog.info(_("Bad Name/Value pair on line: %d in file: %s"),
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200652 lineNr, filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000653 continue;
654 }
655 *value = '\0'; // line only contains the parameter name below.
656 value++;
657
658 bool invalidParameterName = true; // Will be set to false below if
659 // the line contains a valid name.
660
661 if (strcasecmp(line, "ServerName") == 0) {
662
663 if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200664 vlog.info(_("The value of the parameter %s on line %d in file %s "
665 "is invalid."), line, lineNr, filepath);
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200666 continue;
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000667 }
668 snprintf(servername, sizeof(decodingBuffer), "%s", decodingBuffer);
669 invalidParameterName = false;
670
671 } else {
672
673 // Find and set the correct parameter
674 for (int i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
675
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200676 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
677 if (strcasecmp(line, ((StringParameter*)parameterArray[i])->getName()) == 0) {
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000678
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200679 if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
680 vlog.info(_("The value of the parameter %s on line %d in file %s "
681 "is invalid."), line, lineNr, filepath);
682 continue;
683 }
684 ((StringParameter*)parameterArray[i])->setParam(decodingBuffer);
685 invalidParameterName = false;
686 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000687
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200688 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
689 if (strcasecmp(line, ((IntParameter*)parameterArray[i])->getName()) == 0) {
690 ((IntParameter*)parameterArray[i])->setParam(atoi(value));
691 invalidParameterName = false;
692 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000693
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200694 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
695 if (strcasecmp(line, ((BoolParameter*)parameterArray[i])->getName()) == 0) {
696 ((BoolParameter*)parameterArray[i])->setParam(atoi(value));
697 invalidParameterName = false;
698 }
699
700 } else {
701 vlog.info(_("The parameterArray contains a object of a invalid type "
702 "at line %d."), lineNr);
703 }
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000704 }
705 }
706
707 if (invalidParameterName)
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200708 vlog.info(_("Invalid parameter name on line: %d in file: %s"),
Pierre Ossmanffcffd32014-09-22 12:58:48 +0200709 lineNr, filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000710 }
711 fclose(f); f=0;
712
713 return servername;
714}