diff options
author | Peter Åstrand <astrand@cendio.se> | 2012-08-08 11:49:01 +0000 |
---|---|---|
committer | Peter Åstrand <astrand@cendio.se> | 2012-08-08 11:49:01 +0000 |
commit | 8a2b0810dc4a5ad2adc921b6b74a2d6dbdcc6f28 (patch) | |
tree | e4118453fc5774a5346b8ecf7c694fe54c8e0ce4 /vncviewer | |
parent | 49b1157ffb3b50afcb0ccf99d7af5ee8c30e5902 (diff) | |
download | tigervnc-8a2b0810dc4a5ad2adc921b6b74a2d6dbdcc6f28.tar.gz tigervnc-8a2b0810dc4a5ad2adc921b6b74a2d6dbdcc6f28.zip |
Make it possible to load and save configuration files. Also, when
connecting, the options are saved as default settings. This patch
fixes SF bugs 3481470 and 3499216.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4950 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'vncviewer')
-rw-r--r-- | vncviewer/ServerDialog.cxx | 169 | ||||
-rw-r--r-- | vncviewer/ServerDialog.h | 9 | ||||
-rw-r--r-- | vncviewer/parameters.cxx | 577 | ||||
-rw-r--r-- | vncviewer/parameters.h | 4 | ||||
-rw-r--r-- | vncviewer/vncviewer.cxx | 22 |
5 files changed, 756 insertions, 25 deletions
diff --git a/vncviewer/ServerDialog.cxx b/vncviewer/ServerDialog.cxx index 4f21eb1c..25a010a1 100644 --- a/vncviewer/ServerDialog.cxx +++ b/vncviewer/ServerDialog.cxx @@ -1,4 +1,5 @@ /* 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 @@ -25,35 +26,75 @@ #include <FL/Fl_Button.H> #include <FL/Fl_Return_Button.H> #include <FL/fl_draw.H> +#include <FL/fl_ask.H> +#include <FL/Fl_Box.H> +#include <FL/Fl_File_Chooser.H> #include "ServerDialog.h" #include "OptionsDialog.h" #include "fltk_layout.h" #include "i18n.h" #include "vncviewer.h" +#include "parameters.h" +#include "rfb/Exception.h" ServerDialog::ServerDialog() - : Fl_Window(400, 112, _("VNC Viewer: Connection Details")) + : Fl_Window(450, 160, _("VNC Viewer: Connection Details")) { - int width; + int x, y; Fl_Button *button; + Fl_Box *divider; - width = gui_str_len(_("VNC server:")); - serverName = new Fl_Input(20 + width, 20, w() - 20*2 - width, 25, _("VNC server:")); + int margin = 20; + int server_label_width = gui_str_len(_("VNC server:")); - width = (w() - 20) / 4; + x = margin + server_label_width; + y = margin; + + serverName = new Fl_Input(x, y, w() - margin*2 - server_label_width, INPUT_HEIGHT, _("VNC server:")); - button = new Fl_Button(20 + width*0, 20+25+20, width - 20, 27, _("About...")); - button->callback(this->handleAbout, this); + int adjust = (w() - 20) / 4; + int button_width = adjust - margin/2; + + x = margin; + y = margin + margin/2 + INPUT_HEIGHT; + + y += margin/2; - button = new Fl_Button(20 + width*1, 20+25+20, width - 20, 27, _("Options...")); + button = new Fl_Button(x, y, button_width, BUTTON_HEIGHT, _("Options...")); button->callback(this->handleOptions, this); + + x += adjust; + + button = new Fl_Button(x, y, button_width, BUTTON_HEIGHT, _("Load...")); + button->callback(this->handleLoad, this); + + x += adjust; + + button = new Fl_Button(x, y, button_width, BUTTON_HEIGHT, _("Save As...")); + button->callback(this->handleSaveAs, this); + + x = 0; + y += margin/2 + BUTTON_HEIGHT; + + divider = new Fl_Box(x, y, w(), 2); + divider->box(FL_THIN_DOWN_FRAME); + + x += margin; + y += margin/2; + + button = new Fl_Button(x, y, button_width, BUTTON_HEIGHT, _("About...")); + button->callback(this->handleAbout, this); + + x = w() - margin - adjust - button_width - 20; - button = new Fl_Button(20 + width*2, 20+25+20, width - 20, 27, _("Cancel")); + button = new Fl_Button(x, y, button_width, BUTTON_HEIGHT, _("Cancel")); button->callback(this->handleCancel, this); - button = new Fl_Return_Button(20 + width*3, 20+25+20, width - 20, 27, _("OK")); - button->callback(this->handleOK, this); + x += adjust; + + button = new Fl_Return_Button(x, y, button_width+20, BUTTON_HEIGHT, _("Connect")); + button->callback(this->handleConnect, this); callback(this->handleCancel, this); @@ -66,11 +107,13 @@ ServerDialog::~ServerDialog() } -const char *ServerDialog::run() +const char *ServerDialog::run(const char* servername) { ServerDialog dialog; static char buffer[256]; + dialog.serverName->value(servername); + dialog.show(); while (dialog.shown()) Fl::wait(); @@ -83,16 +126,101 @@ const char *ServerDialog::run() return buffer; } +void ServerDialog::handleOptions(Fl_Widget *widget, void *data) +{ + OptionsDialog::showDialog(); +} -void ServerDialog::handleAbout(Fl_Widget *widget, void *data) + +void ServerDialog::handleLoad(Fl_Widget *widget, void *data) { - about_vncviewer(); + ServerDialog *dialog = (ServerDialog*)data; + Fl_File_Chooser* file_chooser = new Fl_File_Chooser("", "TigerVNC configuration (*.tigervnc)", + 0, "Select a TigerVNC configuration file"); + file_chooser->preview(0); + file_chooser->previewButton->hide(); + file_chooser->show(); + + // Block until user picks something. + while(file_chooser->shown()) + Fl::wait(); + + // Did the user hit cancel? + if (file_chooser->value() == NULL) { + delete(file_chooser); + return; + } + + const char* filename = strdup(file_chooser->value()); + + try { + dialog->serverName->value(loadViewerParameters(filename)); + } catch (rfb::Exception& e) { + fl_alert("%s", e.str()); + } + + delete(file_chooser); } -void ServerDialog::handleOptions(Fl_Widget *widget, void *data) +void ServerDialog::handleSaveAs(Fl_Widget *widget, void *data) +{ + ServerDialog *dialog = (ServerDialog*)data; + const char* servername = strdup(dialog->serverName->value()); + char* filename; + + Fl_File_Chooser* file_chooser = new Fl_File_Chooser("", "TigerVNC configuration (*.tigervnc)", + 2, "Save the TigerVNC configuration to file"); + + file_chooser->preview(0); + file_chooser->previewButton->hide(); + file_chooser->show(); + + while(1) { + + // Block until user picks something. + while(file_chooser->shown()) + Fl::wait(); + + // Did the user hit cancel? + if (file_chooser->value() == NULL) { + delete(file_chooser); + return; + } + + filename = strdup(file_chooser->value()); + + FILE* f = fopen(filename, "r"); + if (f) { + + // The file already exists. + fclose(f); + int overwrite_choice = fl_choice("%s already exists. Do you want to overwrite?", + "Overwrite", "No", NULL, filename); + if (overwrite_choice == 1) { + + // If the user doesn't want to overwrite: + file_chooser->show(); + continue; + } + } + + break; + } + + try { + saveViewerParameters(filename, servername); + } catch (rfb::Exception& e) { + fl_alert("%s", e.str()); + } + + delete(file_chooser); +} + + +void ServerDialog::handleAbout(Fl_Widget *widget, void *data) { - OptionsDialog::showDialog(); + about_vncviewer(); } @@ -105,9 +233,16 @@ void ServerDialog::handleCancel(Fl_Widget *widget, void *data) } -void ServerDialog::handleOK(Fl_Widget *widget, void *data) +void ServerDialog::handleConnect(Fl_Widget *widget, void *data) { ServerDialog *dialog = (ServerDialog*)data; + const char* servername = strdup(dialog->serverName->value()); dialog->hide(); + + try { + saveViewerParameters(NULL, servername); + } catch (rfb::Exception& e) { + fl_alert("%s", e.str()); + } } diff --git a/vncviewer/ServerDialog.h b/vncviewer/ServerDialog.h index 052eb62f..402d8ba8 100644 --- a/vncviewer/ServerDialog.h +++ b/vncviewer/ServerDialog.h @@ -21,6 +21,7 @@ #include <FL/Fl_Window.H> #include <FL/Fl_Input.H> +#include <FL/Fl_File_Chooser.H> class ServerDialog : public Fl_Window { protected: @@ -28,13 +29,15 @@ protected: ~ServerDialog(); public: - static const char *run(); + static const char *run(const char* servername); protected: - static void handleAbout(Fl_Widget *widget, void *data); static void handleOptions(Fl_Widget *widget, void *data); + static void handleLoad(Fl_Widget *widget, void *data); + static void handleSaveAs(Fl_Widget *widget, void *data); + static void handleAbout(Fl_Widget *widget, void *data); static void handleCancel(Fl_Widget *widget, void *data); - static void handleOK(Fl_Widget *widget, void *data); + static void handleConnect(Fl_Widget *widget, void *data); protected: Fl_Input *serverName; diff --git a/vncviewer/parameters.cxx b/vncviewer/parameters.cxx index 7b60b621..4c5a3dd6 100644 --- a/vncviewer/parameters.cxx +++ b/vncviewer/parameters.cxx @@ -1,5 +1,6 @@ /* 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 @@ -21,10 +22,33 @@ #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> + using namespace rfb; +static LogWriter vlog("Parameters"); + + IntParameter pointerEventInterval("PointerEventInterval", "Time in milliseconds to rate-limit" " successive pointer events", 0); @@ -107,3 +131,556 @@ BoolParameter fullscreenSystemKeys("FullscreenSystemKeys", "to the server when in full screen mode.", true); +const char* IDENTIFIER_STRING = "TigerVNC Configuration file Version 1.0"; + +VoidParameter* parameterArray[] = { +#ifdef HAVE_GNUTLS + &CSecurityTLS::x509ca, + &CSecurityTLS::x509crl, +#endif // HAVE_GNUTLS + &SecurityClient::secTypes, + &dotWhenNoCursor, + &autoSelect, + &fullColour, + &lowColourLevel, + &preferredEncoding, + &customCompressLevel, + &compressLevel, + &noJpeg, + &qualityLevel, +#ifdef HAVE_FLTK_FULLSCREEN + &fullScreen, +#ifdef HAVE_FLTK_FULLSCREEN_SCREENS + &fullScreenAllMonitors, +#endif // HAVE_FLTK_FULLSCREEN_SCREENS +#endif // HAVE_FLTK_FULLSCREEN + &desktopSize, + &remoteResize, + &viewOnly, + &shared, + &acceptClipboard, + &sendClipboard, + &sendPrimary, + &menuKey, + &fullscreenSystemKeys +}; + +// Encoding Table +static struct { + const char first; + const char second; +} replaceMap[] = {'\n', 'n', + '\r', 'r'}; + +bool encodeValue(const char* val, char* dest, size_t destSize) { + + bool normalCharacter = true; + size_t pos = 0; + + for (int i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) { + + // Check for sequences which will need encoding + if (val[i] == '\\') { + + strncpy(dest+pos, "\\\\", 2); + pos++; + if (pos >= destSize) { + vlog.error("Encoding backslash: The size of the buffer dest is to small, " + "it needs to be more than %d bytes bigger.", (destSize - 1 - i)); + return false; + } + + } else { + + for (int j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) + + if (val[i] == replaceMap[j].first) { + dest[pos] = '\\'; + pos++; + if (pos >= destSize) { + vlog.error("Encoding escape sequence: The size of the buffer dest is to small, " + "it needs to be more than %d bytes bigger.", (destSize - 1 - i)); + return false; + } + + dest[pos] = replaceMap[j].second; + normalCharacter = false; + break; + } + + if (normalCharacter) { + dest[pos] = val[i]; + } + } + normalCharacter = true; // Reset for next loop + + pos++; + if (pos >= destSize) { + vlog.error("Encoding normal character: The size of the buffer dest is to small, " + "it needs to be more than %d bytes bigger.", (destSize - 1 - i)); + return false; + } + + } + + dest[pos] = '\0'; + return true; +} + + +bool decodeValue(const char* val, char* dest, size_t destSize) { + + size_t pos = 0; + bool escapedCharacter = false; + + for (int i = 0; (val[i] != '\0') && (i < (destSize - 1)); i++) { + + // Check for escape sequences + if (val[i] == '\\') { + + for (int j = 0; j < sizeof(replaceMap)/sizeof(replaceMap[0]); j++) { + if (val[i+1] == replaceMap[j].second) { + dest[pos] = replaceMap[j].first; + escapedCharacter = true; + pos--; + break; + } + } + + if (!escapedCharacter) { + if (val[i+1] == '\\') { + dest[pos] = val[i]; + i++; + } else { + vlog.error("Unknown escape sequence at character %d", i); + return false; + } + } + + } else { + dest[pos] = val[i]; + } + + escapedCharacter = false; // Reset for next loop + pos++; + if (pos >= destSize) { + vlog.error("Decoding: The size of the buffer dest is to small, " + "it needs to be 1 byte bigger."); + return false; + } + } + + dest[pos] = '\0'; + return true; +} + + +#ifdef _WIN32 +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("Could not convert the parameter-name %s to wchar_t* when " + "writing to the Registry, the buffersize is to small.", _name); + return; + } + + char encodingBuffer[buffersize]; + if (!encodeValue(_value, encodingBuffer, buffersize)) { + vlog.error("Could not encode the parameter-value %s when " + "writing to the Registry.", _value); + return; + } + + wchar_t value[buffersize]; + size = fl_utf8towc(encodingBuffer, strlen(encodingBuffer)+1, value, buffersize); + if (size >= buffersize) { + vlog.error("Could not convert the parameter-value %s to wchar_t* when " + "writing to the Registry, the buffersize is to small.", _value); + return; + } + + LONG res = RegSetValueExW(*hKey, name, 0, REG_SZ, (BYTE*)&value, (wcslen(value)+1)*2); + if (res != ERROR_SUCCESS) { + vlog.error("Error(%d) writing %s(REG_SZ) to Registry.", res, _value); + return; + } +} + + +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("Could not convert the parameter-name %s to wchar_t* when " + "writing to the Registry, the buffersize is to small.", _name); + return; + } + + LONG res = RegSetValueExW(*hKey, name, 0, REG_DWORD, (BYTE*)&value, sizeof(DWORD)); + if (res != ERROR_SUCCESS) { + vlog.error("Error(%d) writing %d(REG_DWORD) to Registry.", res, _value); + return; + } +} + + +bool getKeyString(const char* _name, char* dest, size_t destSize, HKEY* hKey) { + + DWORD buffersize = 256; + WCHAR value[destSize]; + wchar_t name[buffersize]; + + unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize); + if (size >= buffersize) { + vlog.error("Could not convert the parameter-name %s to wchar_t* when " + "reading from the Registry, the buffersize is to small.", _name); + return false; + } + + LONG res = RegQueryValueExW(*hKey, name, 0, NULL, (LPBYTE)value, &buffersize); + if (res != ERROR_SUCCESS){ + if (res == ERROR_FILE_NOT_FOUND) { + // The value does not exist, defaults will be used. + } else { + vlog.error("Error(%d) reading %s from Registry.", res, _name); + } + return false; + } + + char utf8val[destSize]; + size = fl_utf8fromwc(utf8val, sizeof(utf8val), value, wcslen(value)+1); + if (size >= sizeof(utf8val)) { + vlog.error("Could not convert the parameter-value for %s to utf8 char* " + "when reading from the Registry, the buffer dest is to small.", + _name); + return false; + } + const char *ret = utf8val; + + if(decodeValue(ret, dest, destSize)) + return true; + else + return false; +} + + +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("Could not convert the parameter-name %s to wchar_t* when " + "reading from the Registry, the buffersize is to small.", _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("Error(%d) reading %s from Registry.", res, _name); + } + return false; + } + + *dest = (int)value; + return true; +} + + +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("Error(%d) creating key: Software\\TigerVNC\\vncviewer", res); + return; + } + + setKeyString("ServerName", servername, &hKey); + + for (int 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.info("The parameterArray contains a object of a invalid type at line %d.", i); + } + } + + res = RegCloseKey(hKey); + if (res != ERROR_SUCCESS) { + vlog.error("Error(%d) closing key: Software\\TigerVNC\\vncviewer", res); + } +} + + +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("Error(%d) opening key: Software\\TigerVNC\\vncviewer", 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 (int 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.info("The parameterArray contains a object of a invalid type at line %d.", i); + } + } + + res = RegCloseKey(hKey); + if (res != ERROR_SUCCESS){ + vlog.error("Error(%d) closing key: Software\\TigerVNC\\vncviewer", res); + } + + return servername; +} +#endif // _WIN32 + + +void saveViewerParameters(const char *filename, const char *servername) { + + const size_t buffersize = 256; + char filepath[PATH_MAX]; + char write_error[buffersize*2]; + 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); + } else { + snprintf(filepath, sizeof(filepath), "%s", filename); + } + + /* Write parameters to file */ + FILE* f = fopen(filepath, "w+"); + if (!f) { + snprintf(write_error, sizeof(filepath), "Failed to write configuration file, " + "can't open %s", filepath); + throw Exception(write_error); + } + + fprintf(f, "%s\r\n", IDENTIFIER_STRING); + fprintf(f, "\r\n"); + + if (encodeValue(servername, encodingBuffer, buffersize)) + fprintf(f, "ServerName=%s\n", encodingBuffer); + + for (int 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.info("The parameterArray contains a object of a invalid type at line %d.", i); + } + } + fclose(f); +} + + +char* loadViewerParameters(const char *filename) { + + const size_t buffersize = 256; + char filepath[PATH_MAX]; + char readError[buffersize*2]; + char line[buffersize]; + char decodingBuffer[buffersize]; + char decodedValue[buffersize]; + static char servername[sizeof(line)]; + + // 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); + } else { + snprintf(filepath, sizeof(filepath), "%s", filename); + } + + /* Read parameters from file */ + FILE* f = fopen(filepath, "r"); + if (!f) { + if (!filename) + return NULL; // Use defaults. + snprintf(readError, sizeof(readError), "Failed to read configuration file, " + "can't open %s", filepath); + throw Exception(readError); + } + + int lineNr = 0; + while (!feof(f)) { + + // Read the next line + lineNr++; + if (!fgets(line, sizeof(line), f)) { + if (line[sizeof(line) -1] != '\0') { + vlog.error("Could not read the line(%d) in the configuration file," + "the buffersize is to small.", lineNr); + return NULL; + } + if (feof(f)) + break; + + snprintf(readError, sizeof(readError), "Failed to read line %d in file %s", + lineNr, filepath); + throw Exception(readError); + } + + // 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 { + snprintf(readError, sizeof(readError), "Line 1 in file %s\n" + "must contain the TigerVNC configurationfile identifier string:\n" + "\"%s\"", filepath, IDENTIFIER_STRING); + throw Exception(readError); + } + } + + // 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.info("Bad Name/Value pair on line: %d in file: %s", + lineNr, filepath); + 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.info("The value of the parameter %s on line %d in file %s is invalid.", + line, lineNr, filepath); + continue; + } + snprintf(servername, sizeof(decodingBuffer), "%s", decodingBuffer); + invalidParameterName = false; + + } else { + + // Find and set the correct parameter + for (int 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.info("The value of the parameter %s on line %d in file %s is invalid.", + line, lineNr, filepath); + 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.info("The parameterArray contains a object of a invalid type at line %d.", lineNr); + } + } + } + + if (invalidParameterName) + vlog.info("Invalid parameter name on line: %d in file: %s", + lineNr, filepath); + } + fclose(f); f=0; + + return servername; +} diff --git a/vncviewer/parameters.h b/vncviewer/parameters.h index 5a9170eb..88dd5a8f 100644 --- a/vncviewer/parameters.h +++ b/vncviewer/parameters.h @@ -1,5 +1,6 @@ /* 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 @@ -58,4 +59,7 @@ extern rfb::StringParameter menuKey; extern rfb::BoolParameter fullscreenSystemKeys; +void saveViewerParameters(const char *filename, const char *servername=NULL); +char* loadViewerParameters(const char *filename); + #endif diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx index fd1243ec..79d7935e 100644 --- a/vncviewer/vncviewer.cxx +++ b/vncviewer/vncviewer.cxx @@ -43,6 +43,7 @@ #endif #include <rfb/LogWriter.h> #include <rfb/Timer.h> +#include <rfb/Exception.h> #include <network/TcpSocket.h> #include <os/os.h> @@ -307,6 +308,14 @@ int main(int argc, char** argv) Configuration::enableViewerParams(); + /* Load the default parameter settings */ + const char* defaultServerName; + try { + defaultServerName = loadViewerParameters(NULL); + } catch (rfb::Exception& e) { + fl_alert("%s", e.str()); + } + int i = 1; if (!Fl::args(argc, argv, i) || i < argc) for (; i < argc; i++) { @@ -328,9 +337,10 @@ int main(int argc, char** argv) if (!::autoSelect.hasBeenSet()) { // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used - ::autoSelect.setParam(!::preferredEncoding.hasBeenSet() && - !::fullColour.hasBeenSet() && - !::fullColourAlias.hasBeenSet()); + if (::preferredEncoding.hasBeenSet() || ::fullColour.hasBeenSet() || + ::fullColourAlias.hasBeenSet()) { + ::autoSelect.setParam(false); + } } if (!::fullColour.hasBeenSet() && !::fullColourAlias.hasBeenSet()) { // Default to FullColor=0 if AutoSelect=0 && LowColorLevel is set @@ -341,7 +351,9 @@ int main(int argc, char** argv) } if (!::customCompressLevel.hasBeenSet()) { // Default to CustomCompressLevel=1 if CompressLevel is used. - ::customCompressLevel.setParam(::compressLevel.hasBeenSet()); + if(::compressLevel.hasBeenSet()) { + ::customCompressLevel.setParam(true); + } } mkvnchomedir(); @@ -352,7 +364,7 @@ int main(int argc, char** argv) #endif if (vncServerName == NULL) { - vncServerName = ServerDialog::run(); + vncServerName = ServerDialog::run(defaultServerName); if ((vncServerName == NULL) || (vncServerName[0] == '\0')) return 1; } |