blob: a5c23028457766c94f64f80b05362e6ae362156f [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.
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00003 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19
20// -=- Configuration.cxx
21
22#include <stdlib.h>
23#include <ctype.h>
24#include <string.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000025
Pierre Ossman338e73a2016-07-07 15:35:13 +020026#include <os/Mutex.h>
27
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000028#include <rfb/util.h>
29#include <rfb/Configuration.h>
30#include <rfb/LogWriter.h>
31#include <rfb/Exception.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000032
Pierre Ossman338e73a2016-07-07 15:35:13 +020033#define LOCK_CONFIG os::AutoMutex a(mutex)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000034
35#include <rdr/HexOutStream.h>
36#include <rdr/HexInStream.h>
37
38using namespace rfb;
39
40static LogWriter vlog("Config");
41
42
Adam Tkacc58b3d12010-04-23 13:55:10 +000043// -=- The Global/server/viewer Configuration objects
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000044Configuration* Configuration::global_ = 0;
Adam Tkacc58b3d12010-04-23 13:55:10 +000045Configuration* Configuration::server_ = 0;
46Configuration* Configuration::viewer_ = 0;
47
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000048Configuration* Configuration::global() {
49 if (!global_)
50 global_ = new Configuration("Global");
51 return global_;
52}
53
Adam Tkacc58b3d12010-04-23 13:55:10 +000054Configuration* Configuration::server() {
55 if (!server_)
56 server_ = new Configuration("Server");
57 return server_;
58}
59
60Configuration* Configuration::viewer() {
61 if (!viewer_)
62 viewer_ = new Configuration("Viewer");
63 return viewer_;
64}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000065
66// -=- Configuration implementation
67
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000068bool Configuration::set(const char* n, const char* v, bool immutable) {
69 return set(n, strlen(n), v, immutable);
70}
71
72bool Configuration::set(const char* name, int len,
73 const char* val, bool immutable)
74{
75 VoidParameter* current = head;
76 while (current) {
77 if ((int)strlen(current->getName()) == len &&
78 strncasecmp(current->getName(), name, len) == 0)
79 {
80 bool b = current->setParam(val);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000081 if (b && immutable)
82 current->setImmutable();
83 return b;
84 }
85 current = current->_next;
86 }
87 return _next ? _next->set(name, len, val, immutable) : false;
88}
89
90bool Configuration::set(const char* config, bool immutable) {
91 bool hyphen = false;
92 if (config[0] == '-') {
93 hyphen = true;
94 config++;
95 if (config[0] == '-') config++; // allow gnu-style --<option>
96 }
97 const char* equal = strchr(config, '=');
98 if (equal) {
99 return set(config, equal-config, equal+1, immutable);
100 } else if (hyphen) {
101 VoidParameter* current = head;
102 while (current) {
103 if (strcasecmp(current->getName(), config) == 0) {
104 bool b = current->setParam();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000105 if (b && immutable)
106 current->setImmutable();
107 return b;
108 }
109 current = current->_next;
110 }
111 }
112 return _next ? _next->set(config, immutable) : false;
113}
114
115VoidParameter* Configuration::get(const char* param)
116{
117 VoidParameter* current = head;
118 while (current) {
119 if (strcasecmp(current->getName(), param) == 0)
120 return current;
121 current = current->_next;
122 }
123 return _next ? _next->get(param) : 0;
124}
125
126void Configuration::list(int width, int nameWidth) {
127 VoidParameter* current = head;
128
129 fprintf(stderr, "%s Parameters:\n", name.buf);
130 while (current) {
131 char* def_str = current->getDefaultStr();
132 const char* desc = current->getDescription();
133 fprintf(stderr," %-*s -", nameWidth, current->getName());
134 int column = strlen(current->getName());
135 if (column < nameWidth) column = nameWidth;
136 column += 4;
137 while (true) {
138 const char* s = strchr(desc, ' ');
139 int wordLen;
140 if (s) wordLen = s-desc;
141 else wordLen = strlen(desc);
142
143 if (column + wordLen + 1 > width) {
144 fprintf(stderr,"\n%*s",nameWidth+4,"");
145 column = nameWidth+4;
146 }
147 fprintf(stderr," %.*s",wordLen,desc);
148 column += wordLen + 1;
149 desc += wordLen + 1;
150 if (!s) break;
151 }
152
153 if (def_str) {
154 if (column + (int)strlen(def_str) + 11 > width)
155 fprintf(stderr,"\n%*s",nameWidth+4,"");
156 fprintf(stderr," (default=%s)\n",def_str);
Adam Tkacd36b6262009-09-04 10:57:20 +0000157 strFree(def_str);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000158 } else {
159 fprintf(stderr,"\n");
160 }
161 current = current->_next;
162 }
163
164 if (_next)
165 _next->list(width, nameWidth);
166}
167
168
169// -=- VoidParameter
170
Adam Tkacc58b3d12010-04-23 13:55:10 +0000171VoidParameter::VoidParameter(const char* name_, const char* desc_,
172 ConfigurationObject co)
Pierre Ossman135906e2015-04-27 12:48:47 +0200173 : immutable(false), name(name_), description(desc_)
Adam Tkacc58b3d12010-04-23 13:55:10 +0000174{
175 Configuration *conf = NULL;
176
177 switch (co) {
178 case ConfGlobal: conf = Configuration::global();
179 break;
180 case ConfServer: conf = Configuration::server();
181 break;
182 case ConfViewer: conf = Configuration::viewer();
183 break;
184 }
185
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000186 _next = conf->head;
187 conf->head = this;
Pierre Ossman338e73a2016-07-07 15:35:13 +0200188
189 mutex = new os::Mutex();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000190}
191
192VoidParameter::~VoidParameter() {
Pierre Ossman338e73a2016-07-07 15:35:13 +0200193 delete mutex;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000194}
195
196const char*
197VoidParameter::getName() const {
198 return name;
199}
200
201const char*
202VoidParameter::getDescription() const {
203 return description;
204}
205
206bool VoidParameter::setParam() {
207 return false;
208}
209
210bool VoidParameter::isBool() const {
211 return false;
212}
213
214void
215VoidParameter::setImmutable() {
216 vlog.debug("set immutable %s", getName());
217 immutable = true;
218}
219
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000220// -=- AliasParameter
221
222AliasParameter::AliasParameter(const char* name_, const char* desc_,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000223 VoidParameter* param_, ConfigurationObject co)
224 : VoidParameter(name_, desc_, co), param(param_) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000225}
226
227bool
228AliasParameter::setParam(const char* v) {
229 return param->setParam(v);
230}
231
232bool AliasParameter::setParam() {
233 return param->setParam();
234}
235
236char*
237AliasParameter::getDefaultStr() const {
238 return 0;
239}
240
241char* AliasParameter::getValueStr() const {
242 return param->getValueStr();
243}
244
245bool AliasParameter::isBool() const {
246 return param->isBool();
247}
248
249void
250AliasParameter::setImmutable() {
251 vlog.debug("set immutable %s (Alias)", getName());
252 param->setImmutable();
253}
254
255
256// -=- BoolParameter
257
Adam Tkacc58b3d12010-04-23 13:55:10 +0000258BoolParameter::BoolParameter(const char* name_, const char* desc_, bool v,
259 ConfigurationObject co)
260: VoidParameter(name_, desc_, co), value(v), def_value(v) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000261}
262
263bool
264BoolParameter::setParam(const char* v) {
265 if (immutable) return true;
266
267 if (*v == 0 || strcasecmp(v, "1") == 0 || strcasecmp(v, "on") == 0
268 || strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0)
269 value = 1;
270 else if (strcasecmp(v, "0") == 0 || strcasecmp(v, "off") == 0
271 || strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0)
272 value = 0;
273 else {
274 vlog.error("Bool parameter %s: invalid value '%s'", getName(), v);
275 return false;
276 }
277
278 vlog.debug("set %s(Bool) to %s(%d)", getName(), v, value);
279 return true;
280}
281
282bool BoolParameter::setParam() {
283 setParam(true);
284 return true;
285}
286
287void BoolParameter::setParam(bool b) {
288 if (immutable) return;
289 value = b;
290 vlog.debug("set %s(Bool) to %d", getName(), value);
291}
292
293char*
294BoolParameter::getDefaultStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000295 return strDup(def_value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000296}
297
298char* BoolParameter::getValueStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000299 return strDup(value ? "1" : "0");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000300}
301
302bool BoolParameter::isBool() const {
303 return true;
304}
305
306BoolParameter::operator bool() const {
307 return value;
308}
309
310// -=- IntParameter
311
312IntParameter::IntParameter(const char* name_, const char* desc_, int v,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000313 int minValue_, int maxValue_, ConfigurationObject co)
314 : VoidParameter(name_, desc_, co), value(v), def_value(v),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000315 minValue(minValue_), maxValue(maxValue_)
316{
317}
318
319bool
320IntParameter::setParam(const char* v) {
321 if (immutable) return true;
322 vlog.debug("set %s(Int) to %s", getName(), v);
323 int i = atoi(v);
324 if (i < minValue || i > maxValue)
325 return false;
326 value = i;
327 return true;
328}
329
330bool
331IntParameter::setParam(int v) {
332 if (immutable) return true;
333 vlog.debug("set %s(Int) to %d", getName(), v);
334 if (v < minValue || v > maxValue)
335 return false;
336 value = v;
337 return true;
338}
339
340char*
341IntParameter::getDefaultStr() const {
342 char* result = new char[16];
343 sprintf(result, "%d", def_value);
344 return result;
345}
346
347char* IntParameter::getValueStr() const {
348 char* result = new char[16];
349 sprintf(result, "%d", value);
350 return result;
351}
352
353IntParameter::operator int() const {
354 return value;
355}
356
357// -=- StringParameter
358
359StringParameter::StringParameter(const char* name_, const char* desc_,
Adam Tkacc58b3d12010-04-23 13:55:10 +0000360 const char* v, ConfigurationObject co)
361 : VoidParameter(name_, desc_, co), value(strDup(v)), def_value(v)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000362{
363 if (!v) {
364 fprintf(stderr,"Default value <null> for %s not allowed\n",name_);
365 throw rfb::Exception("Default value <null> not allowed");
366 }
367}
368
369StringParameter::~StringParameter() {
Adam Tkacd36b6262009-09-04 10:57:20 +0000370 strFree(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000371}
372
Adam Tkac3c7f8e12010-11-11 14:29:35 +0000373void StringParameter::setDefaultStr(const char* v) {
374 def_value = v;
375 strFree(value);
376 value = strDup(v);
377}
378
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000379bool StringParameter::setParam(const char* v) {
380 LOCK_CONFIG;
381 if (immutable) return true;
382 if (!v)
383 throw rfb::Exception("setParam(<null>) not allowed");
384 vlog.debug("set %s(String) to %s", getName(), v);
385 CharArray oldValue(value);
Adam Tkacd36b6262009-09-04 10:57:20 +0000386 value = strDup(v);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000387 return value != 0;
388}
389
390char* StringParameter::getDefaultStr() const {
Adam Tkacd36b6262009-09-04 10:57:20 +0000391 return strDup(def_value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000392}
393
394char* StringParameter::getValueStr() const {
395 LOCK_CONFIG;
Adam Tkacd36b6262009-09-04 10:57:20 +0000396 return strDup(value);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000397}
398
Pierre Ossman660f1082011-03-02 12:44:12 +0000399StringParameter::operator const char *() const {
400 return value;
401}
402
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000403// -=- BinaryParameter
404
Adam Tkacc58b3d12010-04-23 13:55:10 +0000405BinaryParameter::BinaryParameter(const char* name_, const char* desc_,
406 const void* v, int l, ConfigurationObject co)
407: VoidParameter(name_, desc_, co), value(0), length(0), def_value((char*)v), def_length(l) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000408 if (l) {
409 value = new char[l];
410 length = l;
411 memcpy(value, v, l);
412 }
413}
414BinaryParameter::~BinaryParameter() {
415 if (value)
416 delete [] value;
417}
418
419bool BinaryParameter::setParam(const char* v) {
420 LOCK_CONFIG;
421 if (immutable) return true;
422 vlog.debug("set %s(Binary) to %s", getName(), v);
423 return rdr::HexInStream::hexStrToBin(v, &value, &length);
424}
425
426void BinaryParameter::setParam(const void* v, int len) {
427 LOCK_CONFIG;
428 if (immutable) return;
429 vlog.debug("set %s(Binary)", getName());
430 delete [] value; value = 0;
431 if (len) {
432 value = new char[len];
433 length = len;
434 memcpy(value, v, len);
435 }
436}
437
438char* BinaryParameter::getDefaultStr() const {
439 return rdr::HexOutStream::binToHexStr(def_value, def_length);
440}
441
442char* BinaryParameter::getValueStr() const {
443 LOCK_CONFIG;
444 return rdr::HexOutStream::binToHexStr(value, length);
445}
446
447void BinaryParameter::getData(void** data_, int* length_) const {
448 LOCK_CONFIG;
449 if (length_) *length_ = length;
450 if (data_) {
451 *data_ = new char[length];
452 memcpy(*data_, value, length);
453 }
454}