2020-09-20 14:16:44 +02:00
|
|
|
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
|
|
|
|
* Copyright 2004-2005 Cendio AB.
|
|
|
|
* Copyright 2017 Peter Astrand <astrand@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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// -=- Configuration.cxx
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
2020-10-01 12:07:32 +02:00
|
|
|
#include <strings.h>
|
2020-09-20 14:16:44 +02:00
|
|
|
|
|
|
|
#include <os/Mutex.h>
|
|
|
|
|
|
|
|
#include <rfb/util.h>
|
|
|
|
#include <rfb/Configuration.h>
|
|
|
|
#include <rfb/LogWriter.h>
|
|
|
|
#include <rfb/Exception.h>
|
|
|
|
|
|
|
|
#define LOCK_CONFIG os::AutoMutex a(mutex)
|
|
|
|
|
|
|
|
#include <rdr/HexOutStream.h>
|
|
|
|
#include <rdr/HexInStream.h>
|
|
|
|
|
|
|
|
using namespace rfb;
|
|
|
|
|
|
|
|
static LogWriter vlog("Config");
|
|
|
|
|
|
|
|
|
|
|
|
// -=- The Global/server/viewer Configuration objects
|
|
|
|
Configuration* Configuration::global_ = 0;
|
|
|
|
Configuration* Configuration::server_ = 0;
|
|
|
|
Configuration* Configuration::viewer_ = 0;
|
|
|
|
|
|
|
|
Configuration* Configuration::global() {
|
|
|
|
if (!global_)
|
|
|
|
global_ = new Configuration("Global");
|
|
|
|
return global_;
|
|
|
|
}
|
|
|
|
|
|
|
|
Configuration* Configuration::server() {
|
|
|
|
if (!server_)
|
|
|
|
server_ = new Configuration("Server");
|
|
|
|
return server_;
|
|
|
|
}
|
|
|
|
|
|
|
|
Configuration* Configuration::viewer() {
|
|
|
|
if (!viewer_)
|
|
|
|
viewer_ = new Configuration("Viewer");
|
|
|
|
return viewer_;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -=- Configuration implementation
|
|
|
|
|
|
|
|
bool Configuration::set(const char* n, const char* v, bool immutable) {
|
|
|
|
return set(n, strlen(n), v, immutable);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Configuration::set(const char* name, int len,
|
|
|
|
const char* val, bool immutable)
|
|
|
|
{
|
|
|
|
VoidParameter* current = head;
|
|
|
|
while (current) {
|
|
|
|
if ((int)strlen(current->getName()) == len &&
|
|
|
|
strncasecmp(current->getName(), name, len) == 0)
|
|
|
|
{
|
|
|
|
bool b = current->setParam(val);
|
|
|
|
if (b && immutable)
|
|
|
|
current->setImmutable();
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
current = current->_next;
|
|
|
|
}
|
|
|
|
return _next ? _next->set(name, len, val, immutable) : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Configuration::set(const char* config, bool immutable) {
|
|
|
|
bool hyphen = false;
|
|
|
|
if (config[0] == '-') {
|
|
|
|
hyphen = true;
|
|
|
|
config++;
|
|
|
|
if (config[0] == '-') config++; // allow gnu-style --<option>
|
|
|
|
}
|
|
|
|
const char* equal = strchr(config, '=');
|
|
|
|
if (equal) {
|
|
|
|
return set(config, equal-config, equal+1, immutable);
|
|
|
|
} else if (hyphen) {
|
|
|
|
VoidParameter* current = head;
|
|
|
|
while (current) {
|
|
|
|
if (strcasecmp(current->getName(), config) == 0) {
|
|
|
|
bool b = current->setParam();
|
|
|
|
if (b && immutable)
|
|
|
|
current->setImmutable();
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
current = current->_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return _next ? _next->set(config, immutable) : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
VoidParameter* Configuration::get(const char* param)
|
|
|
|
{
|
|
|
|
VoidParameter* current = head;
|
|
|
|
while (current) {
|
|
|
|
if (strcasecmp(current->getName(), param) == 0)
|
|
|
|
return current;
|
|
|
|
current = current->_next;
|
|
|
|
}
|
|
|
|
return _next ? _next->get(param) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Configuration::list(int width, int nameWidth) {
|
|
|
|
VoidParameter* current = head;
|
|
|
|
|
|
|
|
fprintf(stderr, "%s Parameters:\n", name.buf);
|
|
|
|
while (current) {
|
|
|
|
char* def_str = current->getDefaultStr();
|
|
|
|
const char* desc = current->getDescription();
|
|
|
|
fprintf(stderr," %-*s -", nameWidth, current->getName());
|
|
|
|
int column = strlen(current->getName());
|
|
|
|
if (column < nameWidth) column = nameWidth;
|
|
|
|
column += 4;
|
|
|
|
while (true) {
|
|
|
|
const char* s = strchr(desc, ' ');
|
|
|
|
int wordLen;
|
|
|
|
if (s) wordLen = s-desc;
|
|
|
|
else wordLen = strlen(desc);
|
|
|
|
|
|
|
|
if (column + wordLen + 1 > width) {
|
|
|
|
fprintf(stderr,"\n%*s",nameWidth+4,"");
|
|
|
|
column = nameWidth+4;
|
|
|
|
}
|
|
|
|
fprintf(stderr," %.*s",wordLen,desc);
|
|
|
|
column += wordLen + 1;
|
|
|
|
desc += wordLen + 1;
|
|
|
|
if (!s) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def_str) {
|
|
|
|
if (column + (int)strlen(def_str) + 11 > width)
|
|
|
|
fprintf(stderr,"\n%*s",nameWidth+4,"");
|
|
|
|
fprintf(stderr," (default=%s)\n",def_str);
|
|
|
|
strFree(def_str);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr,"\n");
|
|
|
|
}
|
|
|
|
current = current->_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_next)
|
|
|
|
_next->list(width, nameWidth);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Configuration::remove(const char* param) {
|
|
|
|
VoidParameter *current = head;
|
|
|
|
VoidParameter **prevnext = &head;
|
|
|
|
|
|
|
|
while (current) {
|
|
|
|
if (strcasecmp(current->getName(), param) == 0) {
|
|
|
|
*prevnext = current->_next;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
prevnext = ¤t->_next;
|
|
|
|
current = current->_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -=- VoidParameter
|
|
|
|
|
|
|
|
VoidParameter::VoidParameter(const char* name_, const char* desc_,
|
|
|
|
ConfigurationObject co)
|
|
|
|
: immutable(false), name(name_), description(desc_)
|
|
|
|
{
|
|
|
|
Configuration *conf = NULL;
|
|
|
|
|
|
|
|
switch (co) {
|
|
|
|
case ConfGlobal: conf = Configuration::global();
|
|
|
|
break;
|
|
|
|
case ConfServer: conf = Configuration::server();
|
|
|
|
break;
|
|
|
|
case ConfViewer: conf = Configuration::viewer();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
_next = conf->head;
|
|
|
|
conf->head = this;
|
|
|
|
|
|
|
|
mutex = new os::Mutex();
|
|
|
|
}
|
|
|
|
|
|
|
|
VoidParameter::~VoidParameter() {
|
|
|
|
delete mutex;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char*
|
|
|
|
VoidParameter::getName() const {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char*
|
|
|
|
VoidParameter::getDescription() const {
|
|
|
|
return description;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VoidParameter::setParam() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VoidParameter::isBool() const {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
VoidParameter::setImmutable() {
|
|
|
|
vlog.debug("set immutable %s", getName());
|
|
|
|
immutable = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -=- AliasParameter
|
|
|
|
|
|
|
|
AliasParameter::AliasParameter(const char* name_, const char* desc_,
|
|
|
|
VoidParameter* param_, ConfigurationObject co)
|
|
|
|
: VoidParameter(name_, desc_, co), param(param_) {
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
AliasParameter::setParam(const char* v) {
|
|
|
|
return param->setParam(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AliasParameter::setParam() {
|
|
|
|
return param->setParam();
|
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
|
|
|
AliasParameter::getDefaultStr() const {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* AliasParameter::getValueStr() const {
|
|
|
|
return param->getValueStr();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AliasParameter::isBool() const {
|
|
|
|
return param->isBool();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
AliasParameter::setImmutable() {
|
|
|
|
vlog.debug("set immutable %s (Alias)", getName());
|
|
|
|
param->setImmutable();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// -=- BoolParameter
|
|
|
|
|
|
|
|
BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v,
|
|
|
|
ConfigurationObject co)
|
|
|
|
: VoidParameter(name_, desc_, co), value(v), def_value(v) {
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
BoolParameter::setParam(const char* v) {
|
|
|
|
if (immutable) return true;
|
|
|
|
|
|
|
|
if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
|
|
|
|
|| strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
|
|
|
|
value = 1;
|
|
|
|
else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
|
|
|
|
|| strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
|
|
|
|
value = 0;
|
|
|
|
else {
|
|
|
|
vlog.error("Bool parameter %s: invalid value '%s'", getName(), v);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
vlog.debug("set %s(Bool) to %s(%d)", getName(), v, value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BoolParameter::setParam() {
|
|
|
|
setParam(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BoolParameter::setParam(bool b) {
|
|
|
|
if (immutable) return;
|
|
|
|
value = b;
|
|
|
|
vlog.debug("set %s(Bool) to %d", getName(), value);
|
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
|
|
|
BoolParameter::getDefaultStr() const {
|
|
|
|
return strDup(def_value ? "1" : "0");
|
|
|
|
}
|
|
|
|
|
|
|
|
char* BoolParameter::getValueStr() const {
|
|
|
|
return strDup(value ? "1" : "0");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BoolParameter::isBool() const {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
BoolParameter::operator bool() const {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -=- PresetParameter
|
|
|
|
|
|
|
|
PresetParameter::PresetParameter(const char* name_, const char* desc_, bool v,
|
|
|
|
void (*onSet)(void),
|
|
|
|
ConfigurationObject co)
|
|
|
|
: BoolParameter(name_, desc_, v, co), onSetCB(onSet) {
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PresetParameter::setParam(const char* value_) {
|
|
|
|
const bool ret = BoolParameter::setParam(value_);
|
|
|
|
|
|
|
|
if (ret && onSetCB && value)
|
|
|
|
onSetCB();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PresetParameter::setParam() {
|
|
|
|
const bool ret = BoolParameter::setParam();
|
|
|
|
|
|
|
|
if (ret && onSetCB && value)
|
|
|
|
onSetCB();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PresetParameter::setParam(bool b) {
|
|
|
|
BoolParameter::setParam(b);
|
|
|
|
|
|
|
|
if (onSetCB && value)
|
|
|
|
onSetCB();
|
|
|
|
}
|
|
|
|
|
|
|
|
// -=- IntParameter
|
|
|
|
|
|
|
|
IntParameter::IntParameter(const char* name_, const char* desc_, int v,
|
|
|
|
int minValue_, int maxValue_, ConfigurationObject co)
|
|
|
|
: VoidParameter(name_, desc_, co), value(v), def_value(v),
|
|
|
|
minValue(minValue_), maxValue(maxValue_)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
IntParameter::setParam(const char* v) {
|
|
|
|
if (immutable) return true;
|
|
|
|
vlog.debug("set %s(Int) to %s", getName(), v);
|
|
|
|
int i = strtol(v, NULL, 0);
|
|
|
|
if (i < minValue || i > maxValue)
|
|
|
|
return false;
|
|
|
|
value = i;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
IntParameter::setParam(int v) {
|
|
|
|
if (immutable) return true;
|
|
|
|
vlog.debug("set %s(Int) to %d", getName(), v);
|
|
|
|
if (v < minValue || v > maxValue)
|
|
|
|
return false;
|
|
|
|
value = v;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
char*
|
|
|
|
IntParameter::getDefaultStr() const {
|
|
|
|
char* result = new char[16];
|
|
|
|
sprintf(result, "%d", def_value);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* IntParameter::getValueStr() const {
|
|
|
|
char* result = new char[16];
|
|
|
|
sprintf(result, "%d", value);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
IntParameter::operator int() const {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -=- StringParameter
|
|
|
|
|
|
|
|
StringParameter::StringParameter(const char* name_, const char* desc_,
|
|
|
|
const char* v, ConfigurationObject co)
|
|
|
|
: VoidParameter(name_, desc_, co), value(strDup(v)), def_value(v)
|
|
|
|
{
|
|
|
|
if (!v) {
|
|
|
|
fprintf(stderr,"Default value <null> for %s not allowed\n",name_);
|
|
|
|
throw rfb::Exception("Default value <null> not allowed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StringParameter::~StringParameter() {
|
|
|
|
strFree(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void StringParameter::setDefaultStr(const char* v) {
|
|
|
|
def_value = v;
|
|
|
|
strFree(value);
|
|
|
|
value = strDup(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool StringParameter::setParam(const char* v) {
|
|
|
|
LOCK_CONFIG;
|
|
|
|
if (immutable) return true;
|
|
|
|
if (!v)
|
|
|
|
throw rfb::Exception("setParam(<null>) not allowed");
|
2020-10-01 12:07:32 +02:00
|
|
|
if (strcasecmp(getName(), "BasicAuth")) // don't log the auth info
|
|
|
|
vlog.debug("set %s(String) to %s", getName(), v);
|
2020-09-20 14:16:44 +02:00
|
|
|
CharArray oldValue(value);
|
|
|
|
value = strDup(v);
|
|
|
|
return value != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* StringParameter::getDefaultStr() const {
|
|
|
|
return strDup(def_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* StringParameter::getValueStr() const {
|
|
|
|
LOCK_CONFIG;
|
|
|
|
return strDup(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
StringParameter::operator const char *() const {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -=- BinaryParameter
|
|
|
|
|
|
|
|
BinaryParameter::BinaryParameter(const char* name_, const char* desc_,
|
2019-09-23 11:00:17 +02:00
|
|
|
const void* v, size_t l, ConfigurationObject co)
|
2020-09-20 14:16:44 +02:00
|
|
|
: VoidParameter(name_, desc_, co), value(0), length(0), def_value((char*)v), def_length(l) {
|
|
|
|
if (l) {
|
|
|
|
value = new char[l];
|
|
|
|
length = l;
|
|
|
|
memcpy(value, v, l);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BinaryParameter::~BinaryParameter() {
|
|
|
|
if (value)
|
|
|
|
delete [] value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BinaryParameter::setParam(const char* v) {
|
|
|
|
LOCK_CONFIG;
|
|
|
|
if (immutable) return true;
|
|
|
|
vlog.debug("set %s(Binary) to %s", getName(), v);
|
|
|
|
return rdr::HexInStream::hexStrToBin(v, &value, &length);
|
|
|
|
}
|
|
|
|
|
2019-09-23 11:00:17 +02:00
|
|
|
void BinaryParameter::setParam(const void* v, size_t len) {
|
2020-09-20 14:16:44 +02:00
|
|
|
LOCK_CONFIG;
|
|
|
|
if (immutable) return;
|
|
|
|
vlog.debug("set %s(Binary)", getName());
|
|
|
|
delete [] value; value = 0;
|
|
|
|
if (len) {
|
|
|
|
value = new char[len];
|
|
|
|
length = len;
|
|
|
|
memcpy(value, v, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char* BinaryParameter::getDefaultStr() const {
|
|
|
|
return rdr::HexOutStream::binToHexStr(def_value, def_length);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* BinaryParameter::getValueStr() const {
|
|
|
|
LOCK_CONFIG;
|
|
|
|
return rdr::HexOutStream::binToHexStr(value, length);
|
|
|
|
}
|
|
|
|
|
2019-09-23 11:00:17 +02:00
|
|
|
void BinaryParameter::getData(void** data_, size_t* length_) const {
|
2020-09-20 14:16:44 +02:00
|
|
|
LOCK_CONFIG;
|
|
|
|
if (length_) *length_ = length;
|
|
|
|
if (data_) {
|
|
|
|
*data_ = new char[length];
|
|
|
|
memcpy(*data_, value, length);
|
|
|
|
}
|
|
|
|
}
|