123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680 |
- /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright 2012 Samuel Mannehed <samuel@cendio.se> for Cendio AB
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
-
- #ifdef HAVE_GNUTLS
- #include <rfb/CSecurityTLS.h>
- #endif
-
- #ifdef _WIN32
- #include <windows.h>
- #include <tchar.h>
- #endif
-
- #include "parameters.h"
-
- #include <os/os.h>
- #include <rfb/Exception.h>
- #include <rfb/LogWriter.h>
- #include <rfb/SecurityClient.h>
-
- #include <FL/fl_utf8.h>
-
- #include <stdio.h>
- #include <string.h>
- #include <limits.h>
- #include <errno.h>
-
- #include "i18n.h"
-
- using namespace rfb;
-
- static LogWriter vlog("Parameters");
-
-
- IntParameter pointerEventInterval("PointerEventInterval",
- "Time in milliseconds to rate-limit"
- " successive pointer events", 17);
- BoolParameter dotWhenNoCursor("DotWhenNoCursor",
- "Show the dot cursor when the server sends an "
- "invisible cursor", false);
-
- BoolParameter alertOnFatalError("AlertOnFatalError",
- "Give a dialog on connection problems rather "
- "than exiting immediately", true);
-
- StringParameter passwordFile("PasswordFile",
- "Password file for VNC authentication", "");
- AliasParameter passwd("passwd", "Alias for PasswordFile", &passwordFile);
-
- BoolParameter autoSelect("AutoSelect",
- "Auto select pixel format and encoding. "
- "Default if PreferredEncoding and FullColor are not specified.",
- true);
- BoolParameter fullColour("FullColor",
- "Use full color", true);
- AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
- IntParameter lowColourLevel("LowColorLevel",
- "Color level to use on slow connections. "
- "0 = Very Low (8 colors), 1 = Low (64 colors), "
- "2 = Medium (256 colors)", 2);
- AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
- StringParameter preferredEncoding("PreferredEncoding",
- "Preferred encoding to use (Tight, ZRLE, Hextile or"
- " Raw)", "Tight");
- BoolParameter customCompressLevel("CustomCompressLevel",
- "Use custom compression level. "
- "Default if CompressLevel is specified.", false);
- IntParameter compressLevel("CompressLevel",
- "Use specified compression level 0 = Low, 6 = High",
- 2);
- BoolParameter noJpeg("NoJPEG",
- "Disable lossy JPEG compression in Tight encoding.",
- false);
- IntParameter qualityLevel("QualityLevel",
- "JPEG quality level. 0 = Low, 9 = High",
- 8);
-
- BoolParameter maximize("Maximize", "Maximize viewer window", false);
- BoolParameter fullScreen("FullScreen", "Full screen mode", false);
- BoolParameter fullScreenAllMonitors("FullScreenAllMonitors",
- "Enable full screen over all monitors",
- true);
- StringParameter desktopSize("DesktopSize",
- "Reconfigure desktop size on the server on "
- "connect (if possible)", "");
- StringParameter geometry("geometry",
- "Specify size and position of viewer window", "");
-
- BoolParameter listenMode("listen", "Listen for connections from VNC servers", false);
-
- BoolParameter remoteResize("RemoteResize",
- "Dynamically resize the remote desktop size as "
- "the size of the local client window changes. "
- "(Does not work with all servers)", true);
-
- BoolParameter viewOnly("ViewOnly",
- "Don't send any mouse or keyboard events to the server",
- false);
- BoolParameter shared("Shared",
- "Don't disconnect other viewers upon connection - "
- "share the desktop instead",
- false);
-
- BoolParameter acceptClipboard("AcceptClipboard",
- "Accept clipboard changes from the server",
- true);
- BoolParameter setPrimary("SetPrimary",
- "Set the primary selection as well as the "
- "clipboard selection", true);
- BoolParameter sendClipboard("SendClipboard",
- "Send clipboard changes to the server", true);
- #if !defined(WIN32) && !defined(__APPLE__)
- BoolParameter sendPrimary("SendPrimary",
- "Send the primary selection to the "
- "server as well as the clipboard selection",
- true);
- StringParameter display("display",
- "Specifies the X display on which the VNC viewer window should appear.",
- "");
- #endif
-
- StringParameter menuKey("MenuKey", "The key which brings up the popup menu",
- "F8");
-
- BoolParameter fullscreenSystemKeys("FullscreenSystemKeys",
- "Pass special keys (like Alt+Tab) directly "
- "to the server when in full screen mode.",
- true);
-
- #ifndef WIN32
- StringParameter via("via", "Gateway to tunnel via", "");
- #endif
-
- static const char* IDENTIFIER_STRING = "TigerVNC Configuration file Version 1.0";
-
- static VoidParameter* parameterArray[] = {
- #ifdef HAVE_GNUTLS
- &CSecurityTLS::X509CA,
- &CSecurityTLS::X509CRL,
- #endif // HAVE_GNUTLS
- &SecurityClient::secTypes,
- &dotWhenNoCursor,
- &autoSelect,
- &fullColour,
- &lowColourLevel,
- &preferredEncoding,
- &customCompressLevel,
- &compressLevel,
- &noJpeg,
- &qualityLevel,
- &fullScreen,
- &fullScreenAllMonitors,
- &desktopSize,
- &geometry,
- &remoteResize,
- &viewOnly,
- &shared,
- &acceptClipboard,
- &sendClipboard,
- #if !defined(WIN32) && !defined(__APPLE__)
- &sendPrimary,
- #endif
- &menuKey,
- &fullscreenSystemKeys,
- &alertOnFatalError
- };
-
- // Encoding Table
- static struct {
- const char first;
- const char second;
- } replaceMap[] = { { '\n', 'n' },
- { '\r', 'r' },
- { '\\', '\\' } };
-
- static bool encodeValue(const char* val, char* dest, size_t destSize) {
-
- size_t pos = 0;
-
- for (size_t i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) {
- bool normalCharacter;
-
- // Check for sequences which will need encoding
- normalCharacter = true;
- for (size_t j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) {
-
- if (val[i] == replaceMap[j].first) {
- dest[pos] = '\\';
- pos++;
- if (pos >= destSize)
- return false;
-
- dest[pos] = replaceMap[j].second;
- normalCharacter = false;
- break;
- }
-
- if (normalCharacter) {
- dest[pos] = val[i];
- }
- }
-
- pos++;
- if (pos >= destSize)
- return false;
- }
-
- dest[pos] = '\0';
- return true;
- }
-
-
- static bool decodeValue(const char* val, char* dest, size_t destSize) {
-
- size_t pos = 0;
-
- for (size_t i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) {
-
- // Check for escape sequences
- if (val[i] == '\\') {
- bool escapedCharacter;
-
- escapedCharacter = false;
- for (size_t j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) {
- if (val[i+1] == replaceMap[j].second) {
- dest[pos] = replaceMap[j].first;
- escapedCharacter = true;
- i++;
- break;
- }
- }
-
- if (!escapedCharacter)
- return false;
-
- } else {
- dest[pos] = val[i];
- }
-
- pos++;
- if (pos >= destSize) {
- return false;
- }
- }
-
- dest[pos] = '\0';
- return true;
- }
-
-
- #ifdef _WIN32
- static void setKeyString(const char *_name, const char *_value, HKEY* hKey) {
-
- const DWORD buffersize = 256;
-
- wchar_t name[buffersize];
- unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
- if (size >= buffersize) {
- vlog.error(_("The name of the parameter %s was too large to write to the registry"), _name);
- return;
- }
-
- char encodingBuffer[buffersize];
- if (!encodeValue(_value, encodingBuffer, buffersize)) {
- vlog.error(_("The parameter %s was too large to write to the registry"), _name);
- return;
- }
-
- wchar_t value[buffersize];
- size = fl_utf8towc(encodingBuffer, strlen(encodingBuffer)+1, value, buffersize);
- if (size >= buffersize) {
- vlog.error(_("The parameter %s was too large to write to the registry"), _name);
- return;
- }
-
- LONG res = RegSetValueExW(*hKey, name, 0, REG_SZ, (BYTE*)&value, (wcslen(value)+1)*2);
- if (res != ERROR_SUCCESS) {
- vlog.error(_("Failed to write parameter %s of type %s to the registry: %ld"),
- _name, "REG_SZ", res);
- return;
- }
- }
-
-
- static void setKeyInt(const char *_name, const int _value, HKEY* hKey) {
-
- const DWORD buffersize = 256;
- wchar_t name[buffersize];
- DWORD value = _value;
-
- unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
- if (size >= buffersize) {
- vlog.error(_("The name of the parameter %s was too large to write to the registry"), _name);
- return;
- }
-
- LONG res = RegSetValueExW(*hKey, name, 0, REG_DWORD, (BYTE*)&value, sizeof(DWORD));
- if (res != ERROR_SUCCESS) {
- vlog.error(_("Failed to write parameter %s of type %s to the registry: %ld"),
- _name, "REG_DWORD", res);
- return;
- }
- }
-
-
- static bool getKeyString(const char* _name, char* dest, size_t destSize, HKEY* hKey) {
-
- const DWORD buffersize = 256;
- wchar_t name[buffersize];
- WCHAR* value;
- DWORD valuesize;
-
- unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
- if (size >= buffersize) {
- vlog.error(_("The name of the parameter %s was too large to read from the registry"), _name);
- return false;
- }
-
- value = new WCHAR[destSize];
- valuesize = destSize;
- LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)value, &valuesize);
- if (res != ERROR_SUCCESS){
- delete [] value;
- if (res == ERROR_FILE_NOT_FOUND) {
- // The value does not exist, defaults will be used.
- } else {
- vlog.error(_("Failed to read parameter %s from the registry: %ld"),
- _name, res);
- }
- return false;
- }
-
- char* utf8val = new char[destSize];
- size = fl_utf8fromwc(utf8val, destSize, value, wcslen(value)+1);
- delete [] value;
- if (size >= destSize) {
- delete [] utf8val;
- vlog.error(_("The parameter %s was too large to read from the registry"), _name);
- return false;
- }
-
- bool ret = decodeValue(utf8val, dest, destSize);
- delete [] utf8val;
-
- return ret;
- }
-
-
- static bool getKeyInt(const char* _name, int* dest, HKEY* hKey) {
-
- const DWORD buffersize = 256;
- DWORD dwordsize = sizeof(DWORD);
- DWORD value = 0;
- wchar_t name[buffersize];
-
- unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
- if (size >= buffersize) {
- vlog.error(_("The name of the parameter %s was too large to read from the registry"), _name);
- return false;
- }
-
- LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)&value, &dwordsize);
- if (res != ERROR_SUCCESS){
- if (res == ERROR_FILE_NOT_FOUND) {
- // The value does not exist, defaults will be used.
- } else {
- vlog.error(_("Failed to read parameter %s from the registry: %ld"),
- _name, res);
- }
- return false;
- }
-
- *dest = (int)value;
- return true;
- }
-
-
- static void saveToReg(const char* servername) {
-
- HKEY hKey;
-
- LONG res = RegCreateKeyExW(HKEY_CURRENT_USER,
- L"Software\\TigerVNC\\vncviewer", 0, NULL,
- REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
- &hKey, NULL);
- if (res != ERROR_SUCCESS) {
- vlog.error(_("Failed to create registry key: %ld"), res);
- return;
- }
-
- setKeyString("ServerName", servername, &hKey);
-
- for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
- if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
- setKeyString(parameterArray[i]->getName(), *(StringParameter*)parameterArray[i], &hKey);
- } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
- setKeyInt(parameterArray[i]->getName(), (int)*(IntParameter*)parameterArray[i], &hKey);
- } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
- setKeyInt(parameterArray[i]->getName(), (int)*(BoolParameter*)parameterArray[i], &hKey);
- } else {
- vlog.error(_("Unknown parameter type for parameter %s"),
- parameterArray[i]->getName());
- }
- }
-
- res = RegCloseKey(hKey);
- if (res != ERROR_SUCCESS) {
- vlog.error(_("Failed to close registry key: %ld"), res);
- }
- }
-
-
- static char* loadFromReg() {
-
- HKEY hKey;
-
- LONG res = RegOpenKeyExW(HKEY_CURRENT_USER,
- L"Software\\TigerVNC\\vncviewer", 0,
- KEY_READ, &hKey);
- if (res != ERROR_SUCCESS) {
- if (res == ERROR_FILE_NOT_FOUND) {
- // The key does not exist, defaults will be used.
- } else {
- vlog.error(_("Failed to open registry key: %ld"), res);
- }
- return NULL;
- }
-
- const size_t buffersize = 256;
- static char servername[buffersize];
-
- char servernameBuffer[buffersize];
- if (getKeyString("ServerName", servernameBuffer, buffersize, &hKey))
- snprintf(servername, buffersize, "%s", servernameBuffer);
-
- int intValue = 0;
- char stringValue[buffersize];
-
- for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
- if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
- if (getKeyString(parameterArray[i]->getName(), stringValue, buffersize, &hKey))
- parameterArray[i]->setParam(stringValue);
- } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
- if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
- ((IntParameter*)parameterArray[i])->setParam(intValue);
- } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
- if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
- ((BoolParameter*)parameterArray[i])->setParam(intValue);
- } else {
- vlog.error(_("Unknown parameter type for parameter %s"),
- parameterArray[i]->getName());
- }
- }
-
- res = RegCloseKey(hKey);
- if (res != ERROR_SUCCESS){
- vlog.error(_("Failed to close registry key: %ld"), res);
- }
-
- return servername;
- }
- #endif // _WIN32
-
-
- void saveViewerParameters(const char *filename, const char *servername) {
-
- const size_t buffersize = 256;
- char filepath[PATH_MAX];
- char encodingBuffer[buffersize];
-
- // Write to the registry or a predefined file if no filename was specified.
- if(filename == NULL) {
-
- #ifdef _WIN32
- saveToReg(servername);
- return;
- #endif
-
- char* homeDir = NULL;
- if (getvnchomedir(&homeDir) == -1) {
- vlog.error(_("Failed to write configuration file, can't obtain home "
- "directory path."));
- return;
- }
-
- snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
- free(homeDir);
- } else {
- snprintf(filepath, sizeof(filepath), "%s", filename);
- }
-
- /* Write parameters to file */
- FILE* f = fopen(filepath, "w+");
- if (!f)
- throw Exception(_("Failed to write configuration file, can't open %s: %s"),
- filepath, strerror(errno));
-
- fprintf(f, "%s\r\n", IDENTIFIER_STRING);
- fprintf(f, "\r\n");
-
- if (encodeValue(servername, encodingBuffer, buffersize))
- fprintf(f, "ServerName=%s\n", encodingBuffer);
-
- for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
- if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
- if (encodeValue(*(StringParameter*)parameterArray[i], encodingBuffer, buffersize))
- fprintf(f, "%s=%s\n", ((StringParameter*)parameterArray[i])->getName(), encodingBuffer);
- } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
- fprintf(f, "%s=%d\n", ((IntParameter*)parameterArray[i])->getName(), (int)*(IntParameter*)parameterArray[i]);
- } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
- fprintf(f, "%s=%d\n", ((BoolParameter*)parameterArray[i])->getName(), (int)*(BoolParameter*)parameterArray[i]);
- } else {
- vlog.error(_("Unknown parameter type for parameter %s"),
- parameterArray[i]->getName());
- }
- }
- fclose(f);
- }
-
-
- char* loadViewerParameters(const char *filename) {
-
- const size_t buffersize = 256;
- char filepath[PATH_MAX];
- char line[buffersize];
- char decodingBuffer[buffersize];
- static char servername[sizeof(line)];
-
- memset(servername, '\0', sizeof(servername));
-
- // Load from the registry or a predefined file if no filename was specified.
- if(filename == NULL) {
-
- #ifdef _WIN32
- return loadFromReg();
- #endif
-
- char* homeDir = NULL;
- if (getvnchomedir(&homeDir) == -1)
- throw Exception(_("Failed to read configuration file, "
- "can't obtain home directory path."));
-
- snprintf(filepath, sizeof(filepath), "%sdefault.tigervnc", homeDir);
- free(homeDir);
- } else {
- snprintf(filepath, sizeof(filepath), "%s", filename);
- }
-
- /* Read parameters from file */
- FILE* f = fopen(filepath, "r");
- if (!f) {
- if (!filename)
- return NULL; // Use defaults.
- throw Exception(_("Failed to read configuration file, can't open %s: %s"),
- filepath, strerror(errno));
- }
-
- int lineNr = 0;
- while (!feof(f)) {
-
- // Read the next line
- lineNr++;
- if (!fgets(line, sizeof(line), f)) {
- if (feof(f))
- break;
-
- throw Exception(_("Failed to read line %d in file %s: %s"),
- lineNr, filepath, strerror(errno));
- }
-
- if (strlen(line) == (sizeof(line) - 1))
- throw Exception(_("Failed to read line %d in file %s: %s"),
- lineNr, filepath, _("Line too long"));
-
- // Make sure that the first line of the file has the file identifier string
- if(lineNr == 1) {
- if(strncmp(line, IDENTIFIER_STRING, strlen(IDENTIFIER_STRING)) == 0)
- continue;
- else
- throw Exception(_("Configuration file %s is in an invalid format"),
- filepath);
- }
-
- // Skip empty lines and comments
- if ((line[0] == '\n') || (line[0] == '#') || (line[0] == '\r'))
- continue;
-
- int len = strlen(line);
- if (line[len-1] == '\n') {
- line[len-1] = '\0';
- len--;
- }
-
- // Find the parameter value
- char *value = strchr(line, '=');
- if (value == NULL) {
- vlog.error(_("Failed to read line %d in file %s: %s"),
- lineNr, filepath, _("Invalid format"));
- continue;
- }
- *value = '\0'; // line only contains the parameter name below.
- value++;
-
- bool invalidParameterName = true; // Will be set to false below if
- // the line contains a valid name.
-
- if (strcasecmp(line, "ServerName") == 0) {
-
- if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
- vlog.error(_("Failed to read line %d in file %s: %s"),
- lineNr, filepath, _("Invalid format or too large value"));
- continue;
- }
- snprintf(servername, sizeof(decodingBuffer), "%s", decodingBuffer);
- invalidParameterName = false;
-
- } else {
-
- // Find and set the correct parameter
- for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
-
- if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
- if (strcasecmp(line, ((StringParameter*)parameterArray[i])->getName()) == 0) {
-
- if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
- vlog.error(_("Failed to read line %d in file %s: %s"),
- lineNr, filepath, _("Invalid format or too large value"));
- continue;
- }
- ((StringParameter*)parameterArray[i])->setParam(decodingBuffer);
- invalidParameterName = false;
- }
-
- } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
- if (strcasecmp(line, ((IntParameter*)parameterArray[i])->getName()) == 0) {
- ((IntParameter*)parameterArray[i])->setParam(atoi(value));
- invalidParameterName = false;
- }
-
- } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
- if (strcasecmp(line, ((BoolParameter*)parameterArray[i])->getName()) == 0) {
- ((BoolParameter*)parameterArray[i])->setParam(atoi(value));
- invalidParameterName = false;
- }
-
- } else {
- vlog.error(_("Unknown parameter type for parameter %s"),
- parameterArray[i]->getName());
- }
- }
- }
-
- if (invalidParameterName)
- vlog.info(_("Unknown parameter %s on line %d in file %s"),
- line, lineNr, filepath);
- }
- fclose(f); f=0;
-
- return servername;
- }
|