blob: 9297a165c7bbafb87b121ade975a6eade8860cb3 [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",
106 "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 Ossman8ca4c1d2014-09-22 12:54:26 +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));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000203 return false;
204 }
205
206 } else {
207
208 for (int j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++)
209
210 if (val[i] == replaceMap[j].first) {
211 dest[pos] = '\\';
212 pos++;
213 if (pos >= destSize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200214 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));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000217 return false;
218 }
219
220 dest[pos] = replaceMap[j].second;
221 normalCharacter = false;
222 break;
223 }
224
225 if (normalCharacter) {
226 dest[pos] = val[i];
227 }
228 }
229 normalCharacter = true; // Reset for next loop
230
231 pos++;
232 if (pos >= destSize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200233 vlog.error(_("Encoding normal character: The size of the buffer dest "
234 "is to small, it needs to be more than %d bytes bigger."),
235 (destSize - 1 - i));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000236 return false;
237 }
238
239 }
240
241 dest[pos] = '\0';
242 return true;
243}
244
245
246bool decodeValue(const char* val, char* dest, size_t destSize) {
247
248 size_t pos = 0;
249 bool escapedCharacter = false;
250
251 for (int i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) {
252
253 // Check for escape sequences
254 if (val[i] == '\\') {
255
256 for (int j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) {
257 if (val[i+1] == replaceMap[j].second) {
258 dest[pos] = replaceMap[j].first;
259 escapedCharacter = true;
260 pos--;
261 break;
262 }
263 }
264
265 if (!escapedCharacter) {
266 if (val[i+1] == '\\') {
267 dest[pos] = val[i];
268 i++;
269 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200270 vlog.error(_("Unknown escape sequence at character %d"), i);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000271 return false;
272 }
273 }
274
275 } else {
276 dest[pos] = val[i];
277 }
278
279 escapedCharacter = false; // Reset for next loop
280 pos++;
281 if (pos >= destSize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200282 vlog.error(_("Decoding: The size of the buffer dest is to small, "
283 "it needs to be 1 byte bigger."));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000284 return false;
285 }
286 }
287
288 dest[pos] = '\0';
289 return true;
290}
291
292
293#ifdef _WIN32
294void setKeyString(const char *_name, const char *_value, HKEY* hKey) {
295
296 const DWORD buffersize = 256;
297
298 wchar_t name[buffersize];
299 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
300 if (size >= buffersize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200301 vlog.error(_("Could not convert the parameter-name %s to wchar_t* when "
302 "writing to the Registry, the buffersize is to small."),
303 _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000304 return;
305 }
306
307 char encodingBuffer[buffersize];
308 if (!encodeValue(_value, encodingBuffer, buffersize)) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200309 vlog.error(_("Could not encode the parameter-value %s when "
310 "writing to the Registry."), _value);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000311 return;
312 }
313
314 wchar_t value[buffersize];
315 size = fl_utf8towc(encodingBuffer, strlen(encodingBuffer)+1, value, buffersize);
316 if (size >= buffersize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200317 vlog.error(_("Could not convert the parameter-value %s to wchar_t* when "
318 "writing to the Registry, the buffersize is to small."),
319 _value);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000320 return;
321 }
322
323 LONG res = RegSetValueExW(*hKey, name, 0, REG_SZ, (BYTE*)&value, (wcslen(value)+1)*2);
324 if (res != ERROR_SUCCESS) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200325 vlog.error(_("Error(%d) writing %s(REG_SZ) to Registry."), res, _value);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000326 return;
327 }
328}
329
330
331void setKeyInt(const char *_name, const int _value, HKEY* hKey) {
332
333 const DWORD buffersize = 256;
334 wchar_t name[buffersize];
335 DWORD value = _value;
336
337 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
338 if (size >= buffersize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200339 vlog.error(_("Could not convert the parameter-name %s to wchar_t* when "
340 "writing to the Registry, the buffersize is to small."),
341 _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000342 return;
343 }
344
345 LONG res = RegSetValueExW(*hKey, name, 0, REG_DWORD, (BYTE*)&value, sizeof(DWORD));
346 if (res != ERROR_SUCCESS) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200347 vlog.error(_("Error(%d) writing %d(REG_DWORD) to Registry."), res, _value);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000348 return;
349 }
350}
351
352
353bool getKeyString(const char* _name, char* dest, size_t destSize, HKEY* hKey) {
354
355 DWORD buffersize = 256;
356 WCHAR value[destSize];
357 wchar_t name[buffersize];
358
359 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
360 if (size >= buffersize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200361 vlog.error(_("Could not convert the parameter-name %s to wchar_t* when "
362 "reading from the Registry, the buffersize is to small."),
363 _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000364 return false;
365 }
366
367 LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)value, &buffersize);
368 if (res != ERROR_SUCCESS){
369 if (res == ERROR_FILE_NOT_FOUND) {
370 // The value does not exist, defaults will be used.
371 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200372 vlog.error(_("Error(%d) reading %s from Registry."), res, _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000373 }
374 return false;
375 }
376
377 char utf8val[destSize];
378 size = fl_utf8fromwc(utf8val, sizeof(utf8val), value, wcslen(value)+1);
379 if (size >= sizeof(utf8val)) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200380 vlog.error(_("Could not convert the parameter-value for %s to utf8 "
381 "char* when reading from the Registry, the buffer dest is "
382 "to small."), _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000383 return false;
384 }
385 const char *ret = utf8val;
386
387 if(decodeValue(ret, dest, destSize))
388 return true;
389 else
390 return false;
391}
392
393
394bool getKeyInt(const char* _name, int* dest, HKEY* hKey) {
395
396 const DWORD buffersize = 256;
397 DWORD dwordsize = sizeof(DWORD);
398 DWORD value = 0;
399 wchar_t name[buffersize];
400
401 unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
402 if (size >= buffersize) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200403 vlog.error(_("Could not convert the parameter-name %s to wchar_t* when "
404 "reading from the Registry, the buffersize is to small."),
405 _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000406 return false;
407 }
408
409 LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)&value, &dwordsize);
410 if (res != ERROR_SUCCESS){
411 if (res == ERROR_FILE_NOT_FOUND) {
412 // The value does not exist, defaults will be used.
413 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200414 vlog.error(_("Error(%d) reading %s from Registry."), res, _name);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000415 }
416 return false;
417 }
418
419 *dest = (int)value;
420 return true;
421}
422
423
424void saveToReg(const char* servername) {
425
426 HKEY hKey;
427
428 LONG res = RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\TigerVNC\\vncviewer", 0, NULL,
429 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
430 if (res != ERROR_SUCCESS) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200431 vlog.error(_("Error(%d) creating key: Software\\TigerVNC\\vncviewer"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000432 return;
433 }
434
435 setKeyString("ServerName", servername, &hKey);
436
437 for (int i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
438 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
439 setKeyString(parameterArray[i]->getName(), *(StringParameter*)parameterArray[i], &hKey);
440 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
441 setKeyInt(parameterArray[i]->getName(), (int)*(IntParameter*)parameterArray[i], &hKey);
442 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
443 setKeyInt(parameterArray[i]->getName(), (int)*(BoolParameter*)parameterArray[i], &hKey);
444 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200445 vlog.info(_("The parameterArray contains a object of a invalid type "
446 "at line %d."), i);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000447 }
448 }
449
450 res = RegCloseKey(hKey);
451 if (res != ERROR_SUCCESS) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200452 vlog.error(_("Error(%d) closing key: Software\\TigerVNC\\vncviewer"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000453 }
454}
455
456
457char* loadFromReg() {
458
459 HKEY hKey;
460
461 LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\TigerVNC\\vncviewer"
462 , 0, KEY_READ, &hKey);
463 if (res != ERROR_SUCCESS) {
464 if (res == ERROR_FILE_NOT_FOUND) {
465 // The key does not exist, defaults will be used.
466 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200467 vlog.error(_("Error(%d) opening key: Software\\TigerVNC\\vncviewer"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000468 }
469 return NULL;
470 }
471
472 const size_t buffersize = 256;
473 static char servername[buffersize];
474
475 char servernameBuffer[buffersize];
476 if (getKeyString("ServerName", servernameBuffer, buffersize, &hKey))
477 snprintf(servername, buffersize, "%s", servernameBuffer);
478
479 int intValue = 0;
480 char stringValue[buffersize];
481
482 for (int i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
483 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
484 if (getKeyString(parameterArray[i]->getName(), stringValue, buffersize, &hKey))
485 parameterArray[i]->setParam(stringValue);
486 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
487 if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
488 ((IntParameter*)parameterArray[i])->setParam(intValue);
489 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
490 if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
491 ((BoolParameter*)parameterArray[i])->setParam(intValue);
492 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200493 vlog.info(_("The parameterArray contains a object of a invalid type at line %d."), i);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000494 }
495 }
496
497 res = RegCloseKey(hKey);
498 if (res != ERROR_SUCCESS){
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200499 vlog.error(_("Error(%d) closing key: Software\\TigerVNC\\vncviewer"), res);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000500 }
501
502 return servername;
503}
504#endif // _WIN32
505
506
507void saveViewerParameters(const char *filename, const char *servername) {
508
509 const size_t buffersize = 256;
510 char filepath[PATH_MAX];
511 char write_error[buffersize*2];
512 char encodingBuffer[buffersize];
513
514 // Write to the registry or a predefined file if no filename was specified.
515 if(filename == NULL) {
516
517#ifdef _WIN32
518 saveToReg(servername);
519 return;
520#endif
521
522 char* homeDir = NULL;
523 if (getvnchomedir(&homeDir) == -1) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200524 vlog.error(_("Failed to write configuration file, can't obtain home "
525 "directory path."));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000526 return;
527 }
528
529 snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
530 } else {
531 snprintf(filepath, sizeof(filepath), "%s", filename);
532 }
533
534 /* Write parameters to file */
535 FILE* f = fopen(filepath, "w+");
536 if (!f) {
Pierre Ossman74d412c2013-07-01 13:59:35 +0000537 snprintf(write_error, sizeof(write_error),
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200538 _("Failed to write configuration file, can't open %s"), filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000539 throw Exception(write_error);
540 }
541
542 fprintf(f, "%s\r\n", IDENTIFIER_STRING);
543 fprintf(f, "\r\n");
544
545 if (encodeValue(servername, encodingBuffer, buffersize))
546 fprintf(f, "ServerName=%s\n", encodingBuffer);
547
548 for (int i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
549 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
550 if (encodeValue(*(StringParameter*)parameterArray[i], encodingBuffer, buffersize))
551 fprintf(f, "%s=%s\n", ((StringParameter*)parameterArray[i])->getName(), encodingBuffer);
552 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
553 fprintf(f, "%s=%d\n", ((IntParameter*)parameterArray[i])->getName(), (int)*(IntParameter*)parameterArray[i]);
554 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
555 fprintf(f, "%s=%d\n", ((BoolParameter*)parameterArray[i])->getName(), (int)*(BoolParameter*)parameterArray[i]);
556 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200557 vlog.info(_("The parameterArray contains a object of a invalid type "
558 "at line %d."), i);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000559 }
560 }
561 fclose(f);
562}
563
564
565char* loadViewerParameters(const char *filename) {
566
567 const size_t buffersize = 256;
568 char filepath[PATH_MAX];
569 char readError[buffersize*2];
570 char line[buffersize];
571 char decodingBuffer[buffersize];
572 char decodedValue[buffersize];
573 static char servername[sizeof(line)];
574
575 // Load from the registry or a predefined file if no filename was specified.
576 if(filename == NULL) {
577
578#ifdef _WIN32
579 return loadFromReg();
580#endif
581
582 char* homeDir = NULL;
583 if (getvnchomedir(&homeDir) == -1)
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200584 throw Exception(_("Failed to read configuration file, "
585 "can't obtain home directory path."));
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000586
587 snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
588 } else {
589 snprintf(filepath, sizeof(filepath), "%s", filename);
590 }
591
592 /* Read parameters from file */
593 FILE* f = fopen(filepath, "r");
594 if (!f) {
595 if (!filename)
596 return NULL; // Use defaults.
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200597 snprintf(readError, sizeof(readError),
598 _("Failed to read configuration file, can't open %s"), filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000599 throw Exception(readError);
600 }
601
602 int lineNr = 0;
603 while (!feof(f)) {
604
605 // Read the next line
606 lineNr++;
607 if (!fgets(line, sizeof(line), f)) {
608 if (line[sizeof(line) -1] != '\0') {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200609 vlog.error(_("Could not read the line(%d) in the configuration file,"
610 "the buffersize is to small."), lineNr);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000611 return NULL;
612 }
613 if (feof(f))
614 break;
615
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200616 snprintf(readError, sizeof(readError),
617 _("Failed to read line %d in file %s"), lineNr, filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000618 throw Exception(readError);
619 }
620
621 // Make sure that the first line of the file has the file identifier string
622 if(lineNr == 1) {
623 if(strncmp(line, IDENTIFIER_STRING, strlen(IDENTIFIER_STRING)) == 0) {
624 continue;
625 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200626 snprintf(readError, sizeof(readError),
627 _("Line 1 in file %s\nmust contain the TigerVNC "
628 "configuration file identifier string:\n"
629 "\"%s\""), filepath, IDENTIFIER_STRING);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000630 throw Exception(readError);
631 }
632 }
633
634 // Skip empty lines and comments
635 if ((line[0] == '\n') || (line[0] == '#') || (line[0] == '\r'))
636 continue;
637
638 int len = strlen(line);
639 if (line[len-1] == '\n') {
640 line[len-1] = '\0';
641 len--;
642 }
643
644 // Find the parameter value
645 char *value = strchr(line, '=');
646 if (value == NULL) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200647 vlog.info(_("Bad Name/Value pair on line: %d in file: %s"),
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000648 lineNr, filepath);
649 continue;
650 }
651 *value = '\0'; // line only contains the parameter name below.
652 value++;
653
654 bool invalidParameterName = true; // Will be set to false below if
655 // the line contains a valid name.
656
657 if (strcasecmp(line, "ServerName") == 0) {
658
659 if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200660 vlog.info(_("The value of the parameter %s on line %d in file %s "
661 "is invalid."), line, lineNr, filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000662 continue;
663 }
664 snprintf(servername, sizeof(decodingBuffer), "%s", decodingBuffer);
665 invalidParameterName = false;
666
667 } else {
668
669 // Find and set the correct parameter
670 for (int i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
671
672 if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
673 if (strcasecmp(line, ((StringParameter*)parameterArray[i])->getName()) == 0) {
674
675 if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200676 vlog.info(_("The value of the parameter %s on line %d in file %s "
677 "is invalid."), line, lineNr, filepath);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000678 continue;
679 }
680 ((StringParameter*)parameterArray[i])->setParam(decodingBuffer);
681 invalidParameterName = false;
682 }
683
684 } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
685 if (strcasecmp(line, ((IntParameter*)parameterArray[i])->getName()) == 0) {
686 ((IntParameter*)parameterArray[i])->setParam(atoi(value));
687 invalidParameterName = false;
688 }
689
690 } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
691 if (strcasecmp(line, ((BoolParameter*)parameterArray[i])->getName()) == 0) {
692 ((BoolParameter*)parameterArray[i])->setParam(atoi(value));
693 invalidParameterName = false;
694 }
695
696 } else {
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200697 vlog.info(_("The parameterArray contains a object of a invalid type "
698 "at line %d."), lineNr);
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000699 }
700 }
701 }
702
703 if (invalidParameterName)
Pierre Ossman8ca4c1d2014-09-22 12:54:26 +0200704 vlog.info(_("Invalid parameter name on line: %d in file: %s"),
Peter Åstrand8a2b0812012-08-08 11:49:01 +0000705 lineNr, filepath);
706 }
707 fclose(f); f=0;
708
709 return servername;
710}