]> source.dussan.org Git - tigervnc.git/commitdiff
Make it possible to load and save configuration files. Also, when
authorPeter Åstrand <astrand@cendio.se>
Wed, 8 Aug 2012 11:49:01 +0000 (11:49 +0000)
committerPeter Åstrand <astrand@cendio.se>
Wed, 8 Aug 2012 11:49:01 +0000 (11:49 +0000)
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

vncviewer/ServerDialog.cxx
vncviewer/ServerDialog.h
vncviewer/parameters.cxx
vncviewer/parameters.h
vncviewer/vncviewer.cxx

index 4f21eb1c331df4f6808495b32d135f9b918de64c..25a010a18afc7951fa323f7daf031ebbd1677de8 100644 (file)
@@ -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
 #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());
+  }
 }
index 052eb62f33d53f9158df5f7e9c2ed1fcd337b851..402d8ba87f42ade7a40ebbfc13183a1666f24f13 100644 (file)
@@ -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;
index 7b60b621bf607df0dacaeb1834f9a42d1dcf74c5..4c5a3dd6a520100ad17e87f80af1ffd978e23a83 100644 (file)
@@ -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
 #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;
+}
index 5a9170eb824c8dc7bed6acb6ae231affefe1477d..88dd5a8fc5225afaa655e81740186068dc4f29d0 100644 (file)
@@ -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
index fd1243ec7b87ae43b8c0c3dcaea2154b68c1cc75..79d7935e4f2296e761de964758f5fc7b37811fa5 100644 (file)
@@ -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;
   }