00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
#include "wvconf.h"
00011
#include "wvfile.h"
00012
#include "wvstringtable.h"
00013
#include <string.h>
00014
#include <sys/stat.h>
00015
00016
00017 void WvConf::setbool(
void *userdata,
00018
WvStringParm sect,
WvStringParm ent,
00019
WvStringParm oldval,
WvStringParm newval)
00020 {
00021
if (!*(
bool *)userdata)
00022 {
00023
WvLog log(
"Config Event", WvLog::Debug);
00024
if(sect ==
"Tunnel Vision" && ent ==
"Magic Password")
00025
log(
"Changed:[%s]%s\n",sect, ent);
00026
else
00027
log(
"Changed: [%s]%s = '%s' -> '%s'\n", sect, ent, oldval, newval);
00028 }
00029
00030 *(
bool *)userdata =
true;
00031 }
00032
00033 void WvConf::addname(
void *userdata,
00034
WvStringParm sect,
WvStringParm ent,
00035
WvStringParm oldval,
WvStringParm newval)
00036 {
00037 (*(
WvStringList *)userdata).append(
new WvString(ent),
true);
00038 }
00039
00040
00041 void WvConf::addfile(
void *userdata,
00042
WvStringParm sect,
WvStringParm ent,
00043
WvStringParm oldval,
WvStringParm newval)
00044 {
00045
WvFile tmp(
WvString(
"/home/%s/%s", ent, *(
WvString *)userdata),
00046 O_WRONLY | O_CREAT | O_TRUNC, 0600);
00047
if(tmp.
isok())
00048 {
00049
if(!!newval)
00050 tmp.
print(
"%s\n", newval);
00051
else
00052 tmp.
print(
"%s\n", ent);
00053 }
00054 }
00055
00056 WvConf::WvConf(
WvStringParm _filename,
int _create_mode)
00057 : filename(_filename),
log(filename), globalsection("")
00058 {
00059 create_mode = _create_mode;
00060 dirty = error = loaded_once =
false;
00061 wvauthd = NULL;
00062
load_file();
00063 }
00064
00065
00066 int WvConf::check_for_bool_string(
const char *s)
00067 {
00068
if (strcasecmp(s,
"off") == 0
00069 || strcasecmp(s,
"false") == 0
00070 || strncasecmp(s,
"no", 2) == 0)
00071
return (0);
00072
00073
if (strcasecmp(s,
"on") == 0
00074 || strcasecmp(s,
"true") == 0
00075 || strcasecmp(s,
"yes") == 0)
00076
return (1);
00077
00078
00079
return (atoi(s));
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 int WvConf::parse_wvconf_request(
char *request,
char *§ion,
00097
char *&entry,
char *&value)
00098 {
00099
00100 entry = value = NULL;
00101
00102 section = strchr(request,
'[');
00103
if (!section)
00104
return -1;
00105
00106 section++;
00107
00108 entry = strchr(section,
']');
00109
if (!entry)
00110
return -2;
00111
00112 *entry++ = 0;
00113
00114 value = strchr(entry,
'=');
00115
if (value)
00116 {
00117 *value++ = 0;
00118 value =
trim_string(value);
00119 }
00120
00121
00122 section =
trim_string(section);
00123 entry =
trim_string(entry);
00124
00125
if (!*section)
00126
return -3;
00127
00128
return 0;
00129 }
00130
00131
00132
00133
00134 int WvConf::getint(
WvStringParm section,
WvStringParm entry,
int def_val)
00135 {
00136
WvString def_str(def_val);
00137
return check_for_bool_string(
get(section, entry, def_str));
00138 }
00139
00140
00141
00142
00143 int WvConf::fuzzy_getint(
WvStringList §ion,
WvStringList &entry,
00144
int def_val)
00145 {
00146
WvString def_str(def_val);
00147
return check_for_bool_string(
fuzzy_get(section, entry, def_str));
00148 }
00149
00150
00151
00152
00153 int WvConf::fuzzy_getint(
WvStringList §ion,
WvStringParm entry,
00154
int def_val)
00155 {
00156
WvString def_str(def_val);
00157
return check_for_bool_string(
fuzzy_get(section, entry, def_str));
00158 }
00159
00160
00161 void WvConf::setint(
WvStringParm section,
WvStringParm entry,
int value)
00162 {
00163
WvString def_str(value);
00164
set(section, entry, def_str);
00165 }
00166
00167
00168
00169 void WvConf::maybesetint(
WvStringParm section,
WvStringParm entry,
00170
int value)
00171 {
00172
if (!
get(section, entry, NULL))
00173
setint(section, entry, value);
00174 }
00175
00176
00177 void WvConf::load_file(
WvStringParm filename)
00178 {
00179
char *p;
00180
char *from_file;
00181
WvConfigSection *sect = &globalsection;
00182
bool quick_mode =
false;
00183
00184
WvFile file(filename, O_RDONLY);
00185
00186
#ifdef _WIN32
00187
00188
00189
#else
00190
00191
struct stat statbuf;
00192
if (file.
isok() && fstat(file.
getrfd(), &statbuf) == -1)
00193 {
00194
log(WvLog::Warning,
"Can't stat config file %s\n", filename);
00195 file.
close();
00196 }
00197
00198
if (file.
isok() && (statbuf.st_mode & S_ISVTX))
00199 {
00200 file.
close();
00201 file.
seterr(EAGAIN);
00202 }
00203
#endif
00204
00205
if (!file.
isok())
00206 {
00207
00208
00209
00210
00211
if (file.
geterr() != ENOENT && !loaded_once)
00212 error =
true;
00213
return;
00214 }
00215
00216
while ((from_file =
trim_string(file.
getline(0))) != NULL)
00217 {
00218
00219
if ((p = parse_section(from_file)) != NULL)
00220 {
00221 quick_mode =
false;
00222
00223
00224
if (!p[0])
00225 sect = &globalsection;
00226
else
00227 {
00228 sect = (*this)[p];
00229
if (!sect)
00230 {
00231 sect =
new WvConfigSection(p);
00232 append(sect,
true);
00233 quick_mode =
true;
00234 }
00235 }
00236 }
00237
else
00238 {
00239
00240 p = parse_value(from_file);
00241
if (!p)
00242 p =
"";
00243
00244 from_file =
trim_string(from_file);
00245
if (from_file[0])
00246 {
00247
if (quick_mode)
00248 sect->
quick_set(from_file, p);
00249
else
00250 sect->
set(from_file, p);
00251 }
00252 }
00253 }
00254
00255
run_all_callbacks();
00256
00257 loaded_once =
true;
00258 }
00259
00260
00261 WvConf::~WvConf()
00262 {
00263
00264
00265
00266
flush();
00267 }
00268
00269
00270 const char *
WvConf::get(
WvStringParm section,
WvStringParm entry,
00271
const char *def_val)
00272 {
00273
WvStringTable cache(5);
00274
WvConfigSection *s;
00275
00276
for(s = (*this)[section];
00277 s && !cache[s->
name];
00278 s = (*s)[
"Inherits"] ? (*this)[(*s)[
"Inherits"]->value] : NULL)
00279 {
00280
const char *ret = s->get(entry);
00281
if (ret)
return ret;
00282 cache.add(&s->name,
false);
00283 }
00284
00285
return globalsection.
get(entry, def_val);
00286 }
00287
00288
00289
00290
00291
00292 WvString WvConf::getraw(
WvString wvconfstr,
int &parse_error)
00293 {
00294
char *section, *entry, *value;
00295 parse_error =
parse_wvconf_request(wvconfstr.
edit(),
00296 section, entry, value);
00297
00298
if (parse_error)
00299
return WvString();
00300
00301
return get(section, entry, value);
00302 }
00303
00304
00305 const char *
WvConf::fuzzy_get(
WvStringList §ions,
WvStringList &entries,
00306
const char *def_val)
00307 {
00308 WvStringList::Iter i(sections), i2(entries);
00309
WvStringTable cache(5);
00310
WvConfigSection *s;
00311
00312
for (i.rewind(); i.next(); )
00313 {
00314
for (i2.rewind(); i2.next();)
00315 {
00316
for(s = (*this)[*i];
00317 s && !cache[s->
name];
00318 s = (*s)[
"Inherits"] ? (*this)[(*s)[
"Inherits"]->value] : NULL)
00319 {
00320
const char *ret = s->get(*i2);
00321
if (ret)
return ret;
00322 cache.add(&s->name,
false);
00323 }
00324 }
00325 }
00326
00327
return def_val;
00328 }
00329
00330
00331 const char *
WvConf::fuzzy_get(
WvStringList §ions,
WvStringParm entry,
00332
const char *def_val)
00333 {
00334 WvStringList::Iter i(sections);
00335
WvStringTable cache(5);
00336
WvConfigSection *s;
00337
00338
for (i.rewind(); i.next(); )
00339 {
00340
for(s = (*this)[*i];
00341 s && !cache[s->
name];
00342 s = (*s)[
"Inherits"] ? (*this)[(*s)[
"Inherits"]->value] : NULL)
00343 {
00344
const char *ret = s->get(entry);
00345
if (ret)
return ret;
00346 cache.add(&s->name,
false);
00347 }
00348 }
00349
00350
return def_val;
00351 }
00352
00353
00354 void WvConf::set(
WvStringParm section,
WvStringParm entry,
00355
const char *value)
00356 {
00357
WvConfigSection *s = (*this)[section];
00358
00359
00360
if (!s)
00361 {
00362
if (!value || !value[0])
00363
return;
00364
00365 s =
new WvConfigSection(section);
00366 append(s,
true);
00367 }
00368
00369
const char *oldval = s->
get(entry,
"");
00370
if (!value) value =
"";
00371
if (strcmp(oldval, value))
00372 {
00373
run_callbacks(section, entry, oldval, value);
00374
00375
00376
00377
00378
00379 s->
set(entry, value);
00380 dirty =
true;
00381 }
00382 }
00383
00384
00385
00386
00387
00388
00389 void WvConf::setraw(
WvString wvconfstr,
const char *&xvalue,
int &parse_error)
00390 {
00391
char *section, *entry, *value;
00392 parse_error =
parse_wvconf_request(wvconfstr.
edit(),
00393 section, entry, value);
00394
if (!parse_error)
00395 {
00396
set(section, entry, value);
00397 xvalue =
get(section, entry, value);
00398 }
00399
else
00400 xvalue = NULL;
00401 }
00402
00403
00404
00405 void WvConf::maybeset(
WvStringParm section,
WvStringParm entry,
00406
const char *value)
00407 {
00408
if (value && !
get(section, entry, NULL))
00409
set(section, entry, value);
00410 }
00411
00412
00413 WvConfigSection *WvConf::operator[] (
WvStringParm section)
00414 {
00415 Iter i(*
this);
00416
00417
if (section)
00418
for (i.rewind(); i.next(); )
00419 {
00420
if (strcasecmp(i().name, section) == 0)
00421
return &i();
00422 }
00423
00424
return NULL;
00425 }
00426
00427
00428 void WvConf::delete_section(
WvStringParm section)
00429 {
00430
WvConfigSection *s = (*this)[section];
00431
if (s)
00432 {
00433 unlink(s);
00434 dirty =
true;
00435 }
00436 }
00437
00438
00439
char *WvConf::parse_section(
char *s)
00440 {
00441
char *q;
00442
00443
if (s[0] !=
'[')
00444
return (NULL);
00445
00446 q = strchr(s,
']');
00447
if (!q || q[1])
00448
return (NULL);
00449
00450 *q = 0;
00451
return trim_string(s + 1);
00452 }
00453
00454
00455
char *WvConf::parse_value(
char *s)
00456 {
00457
char *q;
00458
00459 q = strchr(s,
'=');
00460
if (q == NULL)
00461
return (NULL);
00462
00463 *q++ = 0;
00464
00465
return (
trim_string(q));
00466 }
00467
00468
00469 void WvConf::save(
WvStringParm _filename)
00470 {
00471
if (error || !_filename)
00472
return;
00473
00474
WvFile fp(_filename, O_WRONLY|O_CREAT|O_TRUNC, create_mode);
00475
00476
if (!fp.
isok())
00477 {
00478
log(WvLog::Error,
"Can't write to config file %s: %s\n",
00479 _filename, strerror(errno));
00480
if (fp.
geterr() != ENOENT)
00481 error =
true;
00482
return;
00483 }
00484
00485
#ifdef _WIN32
00486
00487
00488
#else
00489
struct stat statbuf;
00490
if (fstat(fp.
getwfd(), &statbuf) == -1)
00491 {
00492
log(WvLog::Error,
"Can't stat config file %s: %s\n",
00493 _filename, strerror(errno));
00494 error =
true;
00495
return;
00496 }
00497
00498 fchmod(fp.
getwfd(), (statbuf.st_mode & 07777) | S_ISVTX);
00499
#endif
00500
00501 globalsection.
dump(fp);
00502
00503 Iter i(*
this);
00504
for (i.rewind(); i.next();)
00505 {
00506
WvConfigSection & sect = *i;
00507 fp.
print(
"\n[%s]\n", sect.
name);
00508 sect.
dump(fp);
00509 }
00510
00511
#ifdef _WIN32
00512
00513
00514
#else
00515
fchmod(fp.
getwfd(), statbuf.st_mode & 07777);
00516
#endif
00517
}
00518
00519
00520 void WvConf::save()
00521 {
00522
save(filename);
00523 }
00524
00525
00526
00527 void WvConf::flush()
00528 {
00529
if (!dirty || error)
00530
return;
00531
00532
00533
save(filename);
00534
00535 dirty =
false;
00536 }
00537
00538
00539 void WvConf::add_callback(
WvConfCallback callback,
void *userdata,
00540
WvStringParm section,
WvStringParm entry,
00541
void *cookie)
00542 {
00543 callbacks.append(
new WvConfCallbackInfo(callback, userdata,
00544 section, entry, cookie),
true);
00545 }
00546
00547
00548 void WvConf::del_callback(
WvStringParm section,
WvStringParm entry,
00549
void *cookie)
00550 {
00551 WvConfCallbackInfoList::Iter i(callbacks);
00552
00553
for (i.rewind(); i.next(); )
00554 {
00555
if (i->cookie == cookie && i->section == section && i->entry == entry)
00556 {
00557 i.unlink();
00558
return;
00559 }
00560 }
00561 }
00562
00563
00564 void WvConf::run_callbacks(
WvStringParm section,
WvStringParm entry,
00565
WvStringParm oldvalue,
WvStringParm newvalue)
00566 {
00567 WvConfCallbackInfoList::Iter i(callbacks);
00568
00569
for (i.rewind(); i.next(); )
00570 {
00571
if (!i->section || !strcasecmp(i->section, section))
00572 {
00573
if (!i->entry || !strcasecmp(i->entry, entry))
00574 i->callback(i->userdata, section, entry,
00575 oldvalue, newvalue);
00576 }
00577 }
00578 }
00579
00580
00581 void WvConf::run_all_callbacks()
00582 {
00583 WvConfCallbackInfoList::Iter i(callbacks);
00584
00585
for (i.rewind(); i.next(); )
00586 i->callback(i->userdata,
"",
"",
"",
"");
00587 }