blob: ea0006001e5ce9c8f6513223d2b4ed700f964e5f [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Peter Åstrandd69bcc42011-09-28 12:52:53 +00002 * Copyright 2004-2005 Cendio AB.
Peter Åstrand (astrand)0a0e5822017-10-18 08:54:05 +02003 * Copyright 2017 Peter Astrand <astrand@cendio.se> for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00004 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 */
20
21// -=- Configuration.cxx
22
23#include <stdlib.h>
24#include <ctype.h>
25#include <string.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000026
Pierre Ossman338e73a2016-07-07 15:35:13 +020027#include <os/Mutex.h>
28
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000029#include <rfb/util.h>
30#include <rfb/Configuration.h>
31#include <rfb/LogWriter.h>
32#include <rfb/Exception.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000033
Pierre Ossman338e73a2016-07-07 15:35:13 +020034#define LOCK_CONFIG os::AutoMutex a(mutex)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000035
36#include <rdr/HexOutStream.h>
37#include <rdr/HexInStream.h>
38
39using namespace rfb;
40
41static LogWriter vlog("Config");
42
43
Adam Tkacc58b3d12010-04-23 13:55:10 +000044// -=- The Global/server/viewer Configuration objects
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000045Configuration* Configuration::global_ = 0;
Adam Tkacc58b3d12010-04-23 13:55:10 +000046Configuration* Configuration::server_ = 0;
47Configuration* Configuration::viewer_ = 0;
48
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000049Configuration* Configuration::global() {
50 if (!global_)
51 global_ = new Configuration("Global");
52 return global_;
53}
54
Adam Tkacc58b3d12010-04-23 13:55:10 +000055Configuration* Configuration::server() {
56 if (!server_)
57 server_ = new Configuration("Server");
58 return server_;
59}
60
61Configuration* Configuration::viewer() {
62 if (!viewer_)
63 viewer_ = new Configuration("Viewer");
64 return viewer_;
65}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000066
67// -=- Configuration implementation
68
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000069bool Configuration::set(const char* n, const char* v, bool immutable) {
70 return set(n, strlen(n), v, immutable);
71}
72
73bool Configuration::set(const char* name, int len,
74 const char* val, bool immutable)
75{
76 VoidParameter* current = head;
77 while (current) {
78 if ((int)strlen(current->getName()) == len &&
79 strncasecmp(current->getName(), name, len) == 0)
80 {
81 bool b = current->setParam(val);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000082 if (b && immutable)
83 current->setImmutable();
84 return b;
85 }
86 current = current->_next;
87 }
88 return _next ? _next->set(name, len, val, immutable) : false;
89}
90
91bool Configuration::set(const char* config, bool immutable) {
92 bool hyphen = false;
93 if (config[0] == '-') {
94 hyphen = true;
95 config++;
96 if (config[0] == '-') config++; // allow gnu-style --<option>
97 }
98 const char* equal = strchr(config, '=');
99 if (equal) {
100 return set(config, equal-config, equal+1, immutable);
101 } else if (hyphen) {
102 VoidParameter* current = head;
103 while (current) {
104 if (strcasecmp(current->getName(), config) == 0) {
105 bool b = current->setParam();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000106 if (b && immutable)
107 current->setImmutable();
108 return b;
109 }
110 current = current->_next;
111 }
112 }
113 return _next ? _next->set(config, immutable) : false;
114}
115
116VoidParameter* Configuration::get(const char* param)
117{
118 VoidParameter* current = head;
119 while (current) {
120 if (strcasecmp(current->getName(), param) == 0)
121 return current;
122 current = current->_next;
123 }
124 return _next ? _next->get(param) : 0;
125}
126
127void Configuration::list(int width, int nameWidth) {
128 VoidParameter* current = head;
129
130 fprintf(stderr, "%s Parameters:\n", name.buf);
131 while (current) {
132 char* def_str = current->getDefaultStr();
133 const char* desc = current->getDescription();
134 fprintf(stderr," %-*s -", nameWidth, current->getName());
135 int column = strlen(current->getName());
136 if (column < nameWidth) column = nameWidth;
137 column += 4;
138 while (true) {
139 const char* s = strchr(desc, ' ');
140 int wordLen;
141 if (s) wordLen = s-desc;
142 else wordLen = strlen(desc);
143
144 if (column + wordLen + 1 > width) {
145 fprintf(stderr,"\n%*s",nameWidth+4,"");
146 column = nameWidth+4;
147 }
148 fprintf(stderr," %.*s",wordLen,desc);
149 column += wordLen + 1;
150 desc += wordLen + 1;
151 if (!s) break;
152 }
153
154 if (def_str) {
155 if (column + (int)strlen(def_str) + 11 > width)
156 fprintf(stderr,"\n%*s",nameWidth+4,"");
157 fprintf(stderr," (default=%s)\n",def_str);
Adam Tkacd36b6262009-09-04 10:57:20 +0000158 strFree(def_str);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000159 } else {
160 fprintf(stderr,"\n");
161 }
162 current = current->_next;
163 }
164
165 if (_next)
166 _next->list(width, nameWidth);
167}
168
169
Peter Åstrand (astrand)0a0e5822017-10-18 08:54:05 +0200170bool Configuration::remove(const char* param) {
171 VoidParameter *current = head;
172 VoidParameter **prevnext = &head;
173
174 while (current) {
175 if (strcasecmp(current->getName(), param) == 0) {
176 *prevnext = current->_next;
177 return true;
178 }
179 prevnext = &current->_next;
180 current = current->_next;
181 }
182
183 return false;
184}
185
186
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000187// -=- VoidParameter
188
Adam Tkacc58b3d12010-04-23 13:55:10 +0000189VoidParameter::VoidParameter(const char* name_, const char* desc_,
190 ConfigurationObject co)
Pierre Ossman135906e2015-04-27 12:48:47 +0200191 : immutable(false), name(name_), description(desc_)
Adam Tkacc58b3d12010-04-23 13:55:10 +0000192{
193 Configuration *conf = NULL;
194
195 switch (co) {
196 case ConfGlobal: conf = Configuration::global();
197 break;
198 case ConfServer: conf = Configuration::server();
199 break;
200 case ConfViewer: conf = Configuration::viewer();
201 break;
202 }
203
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000204 _next = conf->head;
205 conf->head = this;
Pierre Ossman338e73a2016-07-07 15:35:13 +0200206
207 mutex = new os::Mutex();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000208}
209
210VoidParameter::~VoidParameter() {
Pierre Ossman338e73a2016-07-07 15:35:13 +0200211 delete mutex;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000212}
213
214const char*
215VoidParameter::getName() const {
216 return name;
217}
218
219const char*
220VoidParameter::getDescription() const {
221 return description;
222}
223
224bool VoidParameter::setParam() {
225 return false;
226}
227
228bool VoidParameter::isBool() const {
229 return false;
230}
231
232void
233VoidParameter::setImmutable() {
234 vlog.debug("set immutable %s", getName());
235 immutable = true;
236}
237
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000238// -=- AliasParameter
239
240AliasParameter::AliasParameter(const char* name_, const char* desc_,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000241 VoidParameter* param_, ConfigurationObject co)
242 : VoidParameter(name_, desc_, co), param(param_) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000243}
244
245bool
246AliasParameter::setParam(const char* v) {
247 return param->setParam(v);
248}
249
250bool AliasParameter::setParam() {
251 return param->setParam();
252}
253
254char*
255AliasParameter::getDefaultStr() const {
256 return 0;
257}
258
259char* AliasParameter::getValueStr() const {
260 return param->getValueStr();
261}
262
263bool AliasParameter::isBool() const {
264 return param->isBool();
265}
266
267void
268AliasParameter::setImmutable() {
269 vlog.debug("set immutable %s (Alias)", getName());
270 param->setImmutable();
271}
272
273
274// -=- BoolParameter
275
Adam Tkacc58b3d12010-04-23 13:55:10 +0000276BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v,
277 ConfigurationObject co)
278: VoidParameter(name_, desc_, co), value(v), def_value(v) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000279}
280
281bool
282BoolParameter::setParam(const char* v) {
283 if (immutable) return true;
284
285 if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
286 || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
287 value = 1;
288 else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
289 || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
290 value = 0;
291 else {
292 vlog.error("Bool parameter %s: invalid value '%s'", getName(), v);
293 return false;
294 }
295
296 vlog.debug("set %s(Bool) to %s(%d)", getName(), v, value);
297 return true;
298}
299
300bool BoolParameter::setParam() {
301 setParam(true);
302 return true;
303}
304
305void BoolParameter::setParam(bool b) {
306 if (immutable) return;
307 value = b;
308 vlog.debug("set %s(Bool) to %d", getName(), value);
309}
310
311char*
312BoolParameter::getDefaultStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000313 return strDup(def_value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000314}
315
316char* BoolParameter::getValueStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000317 return strDup(value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000318}
319
320bool BoolParameter::isBool() const {
321 return true;
322}
323
324BoolParameter::operator bool() const {
325 return value;
326}
327
328// -=- IntParameter
329
330IntParameter::IntParameter(const char* name_, const char* desc_, int v,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000331 int minValue_, int maxValue_, ConfigurationObject co)
332 : VoidParameter(name_, desc_, co), value(v), def_value(v),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000333 minValue(minValue_), maxValue(maxValue_)
334{
335}
336
337bool
338IntParameter::setParam(const char* v) {
339 if (immutable) return true;
340 vlog.debug("set %s(Int) to %s", getName(), v);
Pierre Ossmanf36078a2018-05-03 14:00:31 +0200341 int i = strtol(v, NULL, 0);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000342 if (i < minValue || i > maxValue)
343 return false;
344 value = i;
345 return true;
346}
347
348bool
349IntParameter::setParam(int v) {
350 if (immutable) return true;
351 vlog.debug("set %s(Int) to %d", getName(), v);
352 if (v < minValue || v > maxValue)
353 return false;
354 value = v;
355 return true;
356}
357
358char*
359IntParameter::getDefaultStr() const {
360 char* result = new char[16];
361 sprintf(result, "%d", def_value);
362 return result;
363}
364
365char* IntParameter::getValueStr() const {
366 char* result = new char[16];
367 sprintf(result, "%d", value);
368 return result;
369}
370
371IntParameter::operator int() const {
372 return value;
373}
374
375// -=- StringParameter
376
377StringParameter::StringParameter(const char* name_, const char* desc_,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000378 const char* v, ConfigurationObject co)
379 : VoidParameter(name_, desc_, co), value(strDup(v)), def_value(v)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000380{
381 if (!v) {
Pierre Ossmane9e7da92016-04-20 09:38:06 +0200382 vlog.error("Default value <null> for %s not allowed",name_);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000383 throw rfb::Exception("Default value <null> not allowed");
384 }
385}
386
387StringParameter::~StringParameter() {
Adam Tkacd36b6262009-09-04 10:57:20 +0000388 strFree(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000389}
390
Adam Tkac3c7f8e12010-11-11 14:29:35 +0000391void StringParameter::setDefaultStr(const char* v) {
392 def_value = v;
393 strFree(value);
394 value = strDup(v);
395}
396
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000397bool StringParameter::setParam(const char* v) {
398 LOCK_CONFIG;
399 if (immutable) return true;
400 if (!v)
401 throw rfb::Exception("setParam(<null>) not allowed");
402 vlog.debug("set %s(String) to %s", getName(), v);
403 CharArray oldValue(value);
Adam Tkacd36b6262009-09-04 10:57:20 +0000404 value = strDup(v);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000405 return value != 0;
406}
407
408char* StringParameter::getDefaultStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000409 return strDup(def_value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000410}
411
412char* StringParameter::getValueStr() const {
413 LOCK_CONFIG;
Adam Tkacd36b6262009-09-04 10:57:20 +0000414 return strDup(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000415}
416
Pierre Ossman660f1082011-03-02 12:44:12 +0000417StringParameter::operator const char *() const {
418 return value;
419}
420
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000421// -=- BinaryParameter
422
Adam Tkacc58b3d12010-04-23 13:55:10 +0000423BinaryParameter::BinaryParameter(const char* name_, const char* desc_,
424 const void* v, int l, ConfigurationObject co)
425: VoidParameter(name_, desc_, co), value(0), length(0), def_value((char*)v), def_length(l) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000426 if (l) {
427 value = new char[l];
428 length = l;
429 memcpy(value, v, l);
430 }
431}
432BinaryParameter::~BinaryParameter() {
433 if (value)
434 delete [] value;
435}
436
437bool BinaryParameter::setParam(const char* v) {
438 LOCK_CONFIG;
439 if (immutable) return true;
440 vlog.debug("set %s(Binary) to %s", getName(), v);
441 return rdr::HexInStream::hexStrToBin(v, &value, &length);
442}
443
444void BinaryParameter::setParam(const void* v, int len) {
445 LOCK_CONFIG;
446 if (immutable) return;
447 vlog.debug("set %s(Binary)", getName());
448 delete [] value; value = 0;
449 if (len) {
450 value = new char[len];
451 length = len;
452 memcpy(value, v, len);
453 }
454}
455
456char* BinaryParameter::getDefaultStr() const {
457 return rdr::HexOutStream::binToHexStr(def_value, def_length);
458}
459
460char* BinaryParameter::getValueStr() const {
461 LOCK_CONFIG;
462 return rdr::HexOutStream::binToHexStr(value, length);
463}
464
465void BinaryParameter::getData(void** data_, int* length_) const {
466 LOCK_CONFIG;
467 if (length_) *length_ = length;
468 if (data_) {
469 *data_ = new char[length];
470 memcpy(*data_, value, length);
471 }
472}