Revision: 4950
          http://tigervnc.svn.sourceforge.net/tigervnc/?rev=4950&view=rev
Author:   astrand
Date:     2012-08-08 11:49:01 +0000 (Wed, 08 Aug 2012)
Log Message:
-----------
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. 

Modified Paths:
--------------
    trunk/vncviewer/ServerDialog.cxx
    trunk/vncviewer/ServerDialog.h
    trunk/vncviewer/parameters.cxx
    trunk/vncviewer/parameters.h
    trunk/vncviewer/vncviewer.cxx

Modified: trunk/vncviewer/ServerDialog.cxx
===================================================================
--- trunk/vncviewer/ServerDialog.cxx    2012-08-01 08:09:09 UTC (rev 4949)
+++ trunk/vncviewer/ServerDialog.cxx    2012-08-08 11:49:01 UTC (rev 4950)
@@ -1,4 +1,5 @@
 /* Copyright 2011 Pierre Ossman <oss...@cendio.se> for Cendio AB
+ * Copyright 2012 Samuel Mannehed <sam...@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,36 +26,76 @@
 #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;
 
-  button = new Fl_Button(20 + width*1, 20+25+20, width - 20, 27, 
_("Options..."));
+  x = margin;
+  y = margin + margin/2 + INPUT_HEIGHT;
+
+  y += margin/2;
+
+  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);
 
-  button = new Fl_Button(20 + width*2, 20+25+20, width - 20, 27, _("Cancel"));
+  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(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);
 
   set_modal();
@@ -66,11 +107,13 @@
 }
 
 
-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 @@
   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::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());
+  }
 }

Modified: trunk/vncviewer/ServerDialog.h
===================================================================
--- trunk/vncviewer/ServerDialog.h      2012-08-01 08:09:09 UTC (rev 4949)
+++ trunk/vncviewer/ServerDialog.h      2012-08-08 11:49:01 UTC (rev 4950)
@@ -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 @@
   ~ServerDialog();
 
 public:
-  static const char *run();
+  static const char *run(const char* servername);
 
 protected:
+  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 handleOptions(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;

Modified: trunk/vncviewer/parameters.cxx
===================================================================
--- trunk/vncviewer/parameters.cxx      2012-08-01 08:09:09 UTC (rev 4949)
+++ trunk/vncviewer/parameters.cxx      2012-08-08 11:49:01 UTC (rev 4950)
@@ -1,5 +1,6 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright 2011 Pierre Ossman <oss...@cendio.se> for Cendio AB
+ * Copyright 2012 Samuel Mannehed <sam...@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 @@
                                    "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;
+}

Modified: trunk/vncviewer/parameters.h
===================================================================
--- trunk/vncviewer/parameters.h        2012-08-01 08:09:09 UTC (rev 4949)
+++ trunk/vncviewer/parameters.h        2012-08-08 11:49:01 UTC (rev 4950)
@@ -1,5 +1,6 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright 2011 Pierre Ossman <oss...@cendio.se> for Cendio AB
+ * Copyright 2012 Samuel Mannehed <sam...@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::BoolParameter fullscreenSystemKeys;
 
+void saveViewerParameters(const char *filename, const char *servername=NULL);
+char* loadViewerParameters(const char *filename);
+
 #endif

Modified: trunk/vncviewer/vncviewer.cxx
===================================================================
--- trunk/vncviewer/vncviewer.cxx       2012-08-01 08:09:09 UTC (rev 4949)
+++ trunk/vncviewer/vncviewer.cxx       2012-08-08 11:49:01 UTC (rev 4950)
@@ -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 @@
 
   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 @@
 
   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 @@
   }
   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 @@
 #endif
 
   if (vncServerName == NULL) {
-    vncServerName = ServerDialog::run();
+    vncServerName = ServerDialog::run(defaultServerName);
     if ((vncServerName == NULL) || (vncServerName[0] == '\0'))
       return 1;
   }

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Tigervnc-commits mailing list
Tigervnc-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tigervnc-commits

Reply via email to