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 }