~ubuntu-branches/ubuntu/breezy/lurker/breezy

« back to all changes in this revision

Viewing changes to common/ConfigFile.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Meurer
  • Date: 2004-09-26 16:27:51 UTC
  • Revision ID: james.westby@ubuntu.com-20040926162751-z1ohcjltv7ojtg6z
Tags: upstream-1.2
ImportĀ upstreamĀ versionĀ 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  $Id: ConfigFile.cpp,v 1.12 2004/08/27 17:53:44 terpstra Exp $
 
2
 *  
 
3
 *  ConfigFile.cpp - Knows how to load the config file
 
4
 *  
 
5
 *  Copyright (C) 2002 - Wesley W. Terpstra
 
6
 *  
 
7
 *  License: GPL
 
8
 *  
 
9
 *  Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca>
 
10
 *  
 
11
 *    This program is free software; you can redistribute it and/or modify
 
12
 *    it under the terms of the GNU General Public License as published by
 
13
 *    the Free Software Foundation; version 2.
 
14
 *    
 
15
 *    This program is distributed in the hope that it will be useful,
 
16
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 *    GNU General Public License for more details.
 
19
 *    
 
20
 *    You should have received a copy of the GNU General Public License
 
21
 *    along with this program; if not, write to the Free Software
 
22
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
23
 */
 
24
 
 
25
#define _XOPEN_SOURCE 500
 
26
#define _FILE_OFFSET_BITS 64
 
27
 
 
28
#include "ConfigFile.h"
 
29
#include "XmlEscape.h"
 
30
 
 
31
#include <fstream>
 
32
#include <iostream>
 
33
#include <sys/types.h>
 
34
#include <sys/stat.h>
 
35
#include <unistd.h>
 
36
 
 
37
using namespace std;
 
38
 
 
39
map<string, string>* lstring::c = 0;
 
40
 
 
41
lstring::lstring(const string& fallback)
 
42
{
 
43
        s[""] = fallback;
 
44
}
 
45
 
 
46
void lstring::prep_c()
 
47
{
 
48
        c = new map<string, string>();
 
49
        
 
50
        // source: http://www.w3.org/WAI/ER/IG/ert/iso639.htm
 
51
        static const char* code[][2] =
 
52
        {       {"abk", "ab"},
 
53
                {"aar", "aa"},
 
54
                {"afr", "af"},
 
55
                {"alb", "sq"},
 
56
                {"amh", "am"},
 
57
                {"ara", "ar"},
 
58
                {"arm", "hy"},
 
59
                {"asm", "as"},
 
60
                {"aym", "ay"},
 
61
                {"aze", "az"},
 
62
                {"bak", "ba"},
 
63
                {"baq", "eu"},
 
64
                {"ben", "bn"},
 
65
                {"bih", "bh"},
 
66
                {"bis", "bi"},
 
67
                {"bre", "be"},
 
68
                {"bul", "bg"},
 
69
                {"bur", "my"},
 
70
                {"bel", "be"},
 
71
                {"cat", "ca"},
 
72
                {"chi", "zh"},
 
73
                {"cos", "co"},
 
74
                {"ces", "cs"},
 
75
                {"dan", "da"},
 
76
                {"dut", "nl"},
 
77
                {"dzo", "dz"},
 
78
                {"eng", "en"},
 
79
                {"epo", "eo"},
 
80
                {"est", "et"},
 
81
                {"fao", "fo"},
 
82
                {"fij", "fj"},
 
83
                {"fin", "fi"},
 
84
                {"fra", "fr"},
 
85
                {"fry", "fy"},
 
86
                {"glg", "gl"},
 
87
                {"geo", "ka"},
 
88
                {"deu", "de"},
 
89
                {"ell", "el"},
 
90
                {"kal", "kl"},
 
91
                {"grn", "gn"},
 
92
                {"guj", "gu"},
 
93
                {"hau", "ha"},
 
94
                {"heb", "he"},
 
95
                {"hin", "hi"},
 
96
                {"hun", "hu"},
 
97
                {"ice", "is"},
 
98
                {"ind", "id"},
 
99
                {"ina", "ia"},
 
100
                {"iku", "iu"},
 
101
                {"ipk", "ik"},
 
102
                {"gai", "ga"},
 
103
                {"ita", "it"},
 
104
                {"jpn", "ja"},
 
105
                {"jav", "jv"},
 
106
                {"kan", "kn"},
 
107
                {"kas", "ks"},
 
108
                {"kaz", "kk"},
 
109
                {"khm", "km"},
 
110
                {"kin", "rw"},
 
111
                {"kir", "ky"},
 
112
                {"kor", "ko"},
 
113
                {"kur", "ku"},
 
114
                {"oci", "oc"},
 
115
                {"lao", "lo"},
 
116
                {"lat", "la"},
 
117
                {"lav", "lv"},
 
118
                {"lin", "ln"},
 
119
                {"lit", "lt"},
 
120
                {"mac", "mk"},
 
121
                {"mlg", "mg"},
 
122
                {"may", "ms"},
 
123
                {"mlt", "ml"},
 
124
                {"mao", "mi"},
 
125
                {"mar", "mr"},
 
126
                {"mol", "mo"},
 
127
                {"mon", "mn"},
 
128
                {"nau", "na"},
 
129
                {"nep", "ne"},
 
130
                {"nor", "no"},
 
131
                {"ori", "or"},
 
132
                {"orm", "om"},
 
133
                {"pan", "pa"},
 
134
                {"fas", "fa"},
 
135
                {"pol", "pl"},
 
136
                {"por", "pt"},
 
137
                {"pus", "ps"},
 
138
                {"que", "qu"},
 
139
                {"roh", "rm"},
 
140
                {"ron", "ro"},
 
141
                {"run", "rn"},
 
142
                {"rus", "ru"},
 
143
                {"smo", "sm"},
 
144
                {"sag", "sg"},
 
145
                {"san", "sa"},
 
146
                {"scr", "sh"},
 
147
                {"sna", "sn"},
 
148
                {"snd", "sd"},
 
149
                {"sin", "si"},
 
150
                {"ssw", "ss"},
 
151
                {"slk", "sk"},
 
152
                {"slv", "sl"},
 
153
                {"som", "so"},
 
154
                {"sot", "st"},
 
155
                {"esl", "es"},
 
156
                {"sun", "su"},
 
157
                {"swa", "sw"},
 
158
                {"sve", "sv"},
 
159
                {"tgl", "tl"},
 
160
                {"tgk", "tg"},
 
161
                {"tam", "ta"},
 
162
                {"tat", "tt"},
 
163
                {"tel", "te"},
 
164
                {"tha", "th"},
 
165
                {"bod", "bo"},
 
166
                {"tir", "ti"},
 
167
                {"tog", "to"},
 
168
                {"tso", "ts"},
 
169
                {"tsn", "tn"},
 
170
                {"tur", "tr"},
 
171
                {"tuk", "tk"},
 
172
                {"twi", "tw"},
 
173
                {"uig", "ug"},
 
174
                {"ukr", "uk"},
 
175
                {"urd", "ur"},
 
176
                {"uzb", "uz"},
 
177
                {"vie", "vi"},
 
178
                {"vol", "vo"},
 
179
                {"cym", "cy"},
 
180
                {"wol", "wo"},
 
181
                {"xho", "xh"},
 
182
                {"yid", "yi"},
 
183
                {"yor", "yo"},
 
184
                {"zha", "za"},
 
185
                {"zul", "zu"},
 
186
                {"sqi", "sq"},
 
187
                {"hye", "hy"},
 
188
                {"eus", "eu"},
 
189
                {"mya", "my"},
 
190
                {"zho", "zh"},
 
191
                {"cze", "cs"},
 
192
                {"nla", "nl"},
 
193
                {"fre", "fr"},
 
194
                {"kat", "ka"},
 
195
                {"ger", "de"},
 
196
                {"gre", "el"},
 
197
                {"isl", "is"},
 
198
                {"iri", "ga"},
 
199
                {"jaw", "jv"},
 
200
                {"mak", "mk"},
 
201
                {"msa", "ms"},
 
202
                {"mri", "mi"},
 
203
                {"per", "fa"},
 
204
                {"rum", "ro"},
 
205
                {"slo", "sk"},
 
206
                {"spa", "es"},
 
207
                {"swe", "sv"},
 
208
                {"tib", "bo"},
 
209
                {"wel", "cy"},
 
210
                // I think these are the same?
 
211
                {"jw",  "jv"},
 
212
                // ditto
 
213
                {"hr", "scc"},
 
214
                {"sr", "scc"},
 
215
                {"srp", "scc"},
 
216
                {"", ""}
 
217
        };
 
218
        
 
219
        for (unsigned int i = 0; code[i][0] != ""; ++i)
 
220
                (*c)[code[i][0]] = code[i][1];
 
221
}
 
222
 
 
223
bool lstring::lang_normalize(string& lang)
 
224
{
 
225
        if (!c) prep_c();
 
226
        
 
227
        if (lang.length() != 2 && lang.length() != 3)
 
228
                return false;
 
229
        
 
230
        // lower-case it:
 
231
        string iso(lang);
 
232
        for (string::size_type i = 0; i < iso.length(); ++i)
 
233
        {
 
234
                if (iso[i] >= 'A' && iso[i] <= 'Z')
 
235
                        iso[i] = iso[i] - 'A' + 'a';
 
236
                if (iso[i] < 'a' || iso[i] > 'z')
 
237
                        return false; // not an ISO 639 code!
 
238
        }
 
239
        
 
240
        // Resolve different language spellings to one spelling
 
241
        if (c->find(iso) != c->end())
 
242
                lang = (*c)[iso];
 
243
        else    lang = iso;
 
244
        
 
245
        return true;
 
246
}
 
247
        
 
248
bool lstring::locale_normalize(string& locale)
 
249
{
 
250
        string::size_type i, e;
 
251
        
 
252
        if ((e = locale.find('-')) == string::npos &&
 
253
            (e = locale.find('_')) == string::npos)
 
254
                e = locale.length();
 
255
        
 
256
        string lang(locale, 0, e);
 
257
        if (!lang_normalize(lang)) return false;
 
258
        
 
259
        string region;
 
260
        if (e != locale.length())
 
261
        {
 
262
                region.assign(locale, e+1, string::npos);
 
263
                if (region.length() != 2) return false; // not an ISO 3166 code
 
264
                
 
265
                for (i = 0; i < 2; ++i)
 
266
                {
 
267
                        if (region[i] >= 'a' && region[i] <= 'z')
 
268
                                region[i] = region[i] - 'a' + 'A';
 
269
                        if (region[i] < 'A' || region[i] > 'Z')
 
270
                                return false; // not an ISO 3166 code!
 
271
                }
 
272
                
 
273
                locale = lang + "-" + region;
 
274
        }
 
275
        else
 
276
        {
 
277
                locale = lang;
 
278
        }
 
279
        
 
280
        return true;
 
281
}
 
282
 
 
283
bool lstring::translate(const string& language_, const string& translation)
 
284
{
 
285
        string language(language_);
 
286
        if (language != "" && !locale_normalize(language)) return false;
 
287
        
 
288
        string::size_type i;
 
289
        
 
290
        // this overrides whatever we have got so far
 
291
        s[language] = translation;
 
292
        
 
293
        // maybe a localized string for which we lack a language setting?
 
294
        if ((i = language.find('-')) != string::npos)
 
295
        {
 
296
                string iso(language, 0, i);
 
297
                if (s.find(iso) == s.end()) translate(iso, translation);
 
298
        }
 
299
        
 
300
        // maybe we lack a fallback language completely
 
301
        if (s.find("") == s.end()) translate("", translation);
 
302
        
 
303
        return true;
 
304
}
 
305
 
 
306
string lstring::localize(const string& language_) const
 
307
{
 
308
        string language(language_);
 
309
        if (language != "" && !locale_normalize(language)) return "(bug) bad locale";
 
310
        
 
311
        map<string, string>::const_iterator o;
 
312
        string::size_type i;
 
313
        
 
314
        // correct locale? use it
 
315
        if ((o = s.find(language)) != s.end()) return o->second;
 
316
        
 
317
        // correct language? use it
 
318
        if ((i = language.find('-')) != string::npos)
 
319
        {
 
320
                string iso(language, 0, i);
 
321
                if ((o = s.find(iso)) != s.end()) return o->second;
 
322
        }
 
323
        
 
324
        // fallback? use it
 
325
        if ((o = s.find("")) != s.end()) return o->second;
 
326
        
 
327
        return ""; // not set!
 
328
}
 
329
 
 
330
bool lstring::is_set() const
 
331
{
 
332
        return !s.empty();
 
333
}
 
334
 
 
335
Config::Config()
 
336
 : list(0), group("lists"), error(), lists(), groups(),
 
337
   dbdir(""), 
 
338
   xslt("cat -"),
 
339
   pgpv_mime("off"),
 
340
   pgpv_inline("off"),
 
341
   admin_address(""),
 
342
   
 
343
   archive("Unconfigured Archivew"),
 
344
   admin_name("Unset admin name"),
 
345
   web_cache(true),
 
346
   hide_email(false),
 
347
   raw_email(true),
 
348
   regroupable(true),
 
349
   modified(0)
 
350
{
 
351
}
 
352
 
 
353
void prune_back(string& line)
 
354
{
 
355
        // Trim off eol and whitespace
 
356
        string::size_type whitespace = line.length();
 
357
        while (whitespace > 0 &&
 
358
                (line[whitespace-1] == ' '  ||
 
359
                 line[whitespace-1] == '\r' ||
 
360
                 line[whitespace-1] == '\n' ||
 
361
                 line[whitespace-1] == '\t'))
 
362
                whitespace--;
 
363
        
 
364
        line.resize(whitespace);
 
365
}
 
366
 
 
367
string::size_type skip_front(const string& line, string::size_type x = 0)
 
368
{
 
369
        // Trim off eol and whitespace
 
370
        for (; x < line.length(); ++x)
 
371
                if (line[x] != ' '  &&
 
372
                    line[x] != '\r' &&
 
373
                    line[x] != '\n' &&
 
374
                    line[x] != '\t')
 
375
                        break;
 
376
        
 
377
        return x;
 
378
}
 
379
 
 
380
int Config::load(const string& file, bool toplevel)
 
381
{
 
382
        ifstream f(file.c_str());
 
383
        if (!f.is_open())
 
384
        {
 
385
                error << file << ":open: could not open!" << endl;
 
386
                return -1;
 
387
        }
 
388
        
 
389
        struct stat sbuf;
 
390
        if (stat(file.c_str(), &sbuf) < 0)
 
391
        {
 
392
                error << file << ":stat: could not stat!" << endl;
 
393
                return -1;
 
394
        }
 
395
        
 
396
        // deal with included file's timestamps
 
397
        if (sbuf.st_mtime > modified)
 
398
                modified = sbuf.st_mtime;
 
399
        
 
400
        string dir;
 
401
        string::size_type x = file.rfind('/');
 
402
        if (x != string::npos) dir.assign(file, 0, x+1);
 
403
        
 
404
        string line;
 
405
        bool ok = true;
 
406
        int c = 0;
 
407
        
 
408
        string val, key;
 
409
        
 
410
        while (getline(f, line))
 
411
        {
 
412
                // Increment line number
 
413
                ++c;
 
414
                
 
415
                // Trim off the comments
 
416
                string::size_type comment = line.find('#');
 
417
                if (comment != string::npos) line.resize(comment);
 
418
                
 
419
                // Clear off trailing whitespace
 
420
                prune_back(line);
 
421
                
 
422
                // skip empty lines
 
423
                if (line.length() == 0) continue;
 
424
                
 
425
                string::size_type eq = line.find('=');
 
426
                if (eq == string::npos)
 
427
                {       // this line continues the previous one.
 
428
                        if (key == "")
 
429
                        {
 
430
                                error << "No key for value '" << line << "'!" << endl;
 
431
                                ok = false;
 
432
                        }
 
433
                        else
 
434
                        {
 
435
                                string::size_type fe = skip_front(line);
 
436
                                val.append(" ");
 
437
                                val.append(line, fe, string::npos);
 
438
                        }
 
439
                }
 
440
                else
 
441
                {
 
442
                        if (key != "" && process_command(key, val, dir) != 0) ok = false;
 
443
                        
 
444
                        string::size_type leadin = skip_front(line);
 
445
                        key.assign(line, leadin, eq-leadin);
 
446
                        val.assign(line, skip_front(line, eq+1), string::npos);
 
447
                        prune_back(key);
 
448
                }
 
449
        }
 
450
        
 
451
        if (toplevel && key == "")
 
452
        {
 
453
                error << "No values set by config file '" << file << "'!" << endl;
 
454
                ok = false;
 
455
        }
 
456
        
 
457
        if (key != "" && process_command(key, val, dir) != 0) ok = false;
 
458
        
 
459
        if (!ok) return -1;
 
460
        return 0;
 
461
}
 
462
 
 
463
bool isSimple(const string& s)
 
464
{
 
465
        string::size_type x;
 
466
        for (x = 0; x < s.length(); ++x)
 
467
        {
 
468
                char y = s[x];
 
469
                if (y >= 'a' && y <= 'z') continue;
 
470
                if (y >= '0' && y <= '9') continue;
 
471
                if (y == '.' || y == '-' || y == '_') continue;
 
472
                return false;
 
473
        }
 
474
        
 
475
        return true;
 
476
}
 
477
 
 
478
int Config::process_command(const string& keys, const string& val, const string& dir)
 
479
{
 
480
//      cout << key << "-" << val << endl;
 
481
        
 
482
        string lc; // locale code
 
483
        string key(keys);
 
484
        
 
485
        string::size_type o, c;
 
486
        if ((o = key.find('[')) != string::npos &&
 
487
            (c = key.find(']')) != string::npos &&
 
488
            c > o)
 
489
        {
 
490
                // localization option
 
491
                lc.assign(key, o+1, (c-o) - 1);
 
492
                key.erase(o, (c-o) + 1);
 
493
                
 
494
                if (!lstring::locale_normalize(lc))
 
495
                {
 
496
                        error << "Localization code '" << lc << "' is not valid." << endl;
 
497
                        return -1;
 
498
                }
 
499
        }
 
500
        
 
501
        string::size_type len = string::npos;
 
502
        
 
503
        if (key == "group")
 
504
        {
 
505
                len = 32;
 
506
                if (!isSimple(val) || val.length() == 0)
 
507
                {
 
508
                        error << "Group id '" << val << "' is not a simple lowercase string!" << endl;
 
509
                        return -1;
 
510
                }
 
511
                
 
512
                if (lc != "")
 
513
                {
 
514
                        error << "group id cannot be localized" << endl;
 
515
                        return -1;
 
516
                }
 
517
                
 
518
                group = val;
 
519
        }
 
520
        else if (key == "heading")
 
521
        {
 
522
                len = 60;
 
523
                groups[group].heading.translate(lc, val);
 
524
        }
 
525
        else if (key == "list")
 
526
        {
 
527
                len = 32;
 
528
                if (!isSimple(val) || val.length() == 0)
 
529
                {
 
530
                        error << "List id '" << val << "' is not a simple lowercase string!" << endl;
 
531
                        return -1;
 
532
                }
 
533
                if (lc != "")
 
534
                {
 
535
                        error << "list id cannot be localized" << endl;
 
536
                        return -1;
 
537
                }
 
538
                
 
539
                if (lists.find(val) == lists.end())
 
540
                {
 
541
                        groups[group].members.insert(val);
 
542
                        list = &lists[val];
 
543
                        list->mbox = val;
 
544
                        list->group = group;
 
545
                        list->language = "en";
 
546
                        list->offline = false;
 
547
                }
 
548
                else
 
549
                {
 
550
                        // re-enter list scope
 
551
                        list = &lists[val];
 
552
                }
 
553
        }
 
554
        else if (key == "title")
 
555
        {
 
556
                len = 40;
 
557
                
 
558
                if (!list)
 
559
                {
 
560
                        error << "No list has been defined for title '" << val << "'!" << endl;
 
561
                        return -1;
 
562
                }
 
563
                
 
564
                list->title.translate(lc, val);
 
565
        }
 
566
        else if (key == "address")
 
567
        {
 
568
                if (!list)
 
569
                {
 
570
                        error << "No list has been defined for address '" << val << "'!" << endl;
 
571
                        return -1;
 
572
                }
 
573
                if (lc != "")
 
574
                {
 
575
                        error << "list address cannot be localized" << endl;
 
576
                        return -1;
 
577
                }
 
578
                
 
579
                list->address = val;
 
580
        }
 
581
        else if (key == "link")
 
582
        {
 
583
                if (!list)
 
584
                {
 
585
                        error << "No list has been defined for address '" << val << "'!" << endl;
 
586
                        return -1;
 
587
                }
 
588
                
 
589
                list->link.translate(lc, val);
 
590
        }
 
591
        else if (key == "language")
 
592
        {
 
593
                if (!list)
 
594
                {
 
595
                        error << "No list has been defined for language '" << val << "'!" << endl;
 
596
                        return -1;
 
597
                }
 
598
                if (lc != "")
 
599
                {
 
600
                        error << "list language cannot be localized" << endl;
 
601
                        return -1;
 
602
                }
 
603
                
 
604
                string lval(val);
 
605
                if (!lstring::lang_normalize(lval))
 
606
                {
 
607
                        error << "Language '" << val << "' is not an ISO 639 language code!" << endl;
 
608
                        error << "Regional variants are not relevant for searches." << endl;
 
609
                        return -1;
 
610
                }
 
611
                
 
612
                list->language = lval;
 
613
        }
 
614
        else if (key == "offline")
 
615
        {
 
616
                if (!list)
 
617
                {
 
618
                        error << "No list has been defined for offline setting '" << val << "'!" << endl;
 
619
                        return -1;
 
620
                }
 
621
                if (lc != "")
 
622
                {
 
623
                        error << "list offline cannot be localized" << endl;
 
624
                        return -1;
 
625
                }
 
626
                
 
627
                if (val == "off" || val == "false")
 
628
                        list->offline = false;
 
629
                else if (val == "on" || val == "true")
 
630
                        list->offline = true;
 
631
                else
 
632
                {
 
633
                        error << "offline must be set to on/off or true/false!" << endl;
 
634
                        return -1;
 
635
                }
 
636
        }
 
637
        else if (key == "description")
 
638
        {
 
639
                if (!list)
 
640
                {
 
641
                        error << "No list has been defined for address '" << val << "'!" << endl;
 
642
                        return -1;
 
643
                }
 
644
                
 
645
                list->description.translate(lc, val);
 
646
        }
 
647
        else if (key == "dbdir")
 
648
        {
 
649
                if (lc != "")
 
650
                {
 
651
                        error << "dbdir cannot be localized" << endl;
 
652
                        return -1;
 
653
                }
 
654
                dbdir = val;
 
655
        }
 
656
        else if (key == "admin_name")
 
657
        {
 
658
                admin_name.translate(lc, val);
 
659
        }
 
660
        else if (key == "admin_address")
 
661
        {
 
662
                if (lc != "")
 
663
                {
 
664
                        error << "admin_address cannot be localized" << endl;
 
665
                        return -1;
 
666
                }
 
667
                admin_address = val;
 
668
        }
 
669
        else if (key == "archive")
 
670
        {
 
671
                archive.translate(lc, val);
 
672
        }
 
673
        else if (key == "xslt")
 
674
        {
 
675
                if (lc != "")
 
676
                {
 
677
                        error << "xslt command cannot be localized" << endl;
 
678
                        return -1;
 
679
                }
 
680
                xslt = val;
 
681
        }
 
682
        else if (key == "pgp_verify_mime")
 
683
        {
 
684
                if (lc != "")
 
685
                {
 
686
                        error << "pgp_verify_mime command cannot be localized" << endl;
 
687
                        return -1;
 
688
                }
 
689
                pgpv_mime = val;
 
690
        }
 
691
        else if (key == "pgp_verify_inline")
 
692
        {
 
693
                if (lc != "")
 
694
                {
 
695
                        error << "pgp_verify_inline command cannot be localized" << endl;
 
696
                        return -1;
 
697
                }
 
698
                pgpv_inline = val;
 
699
        }
 
700
        else if (key == "web_cache")
 
701
        {
 
702
                if (lc != "")
 
703
                {
 
704
                        error << "web_cache cannot be localized" << endl;
 
705
                        return -1;
 
706
                }
 
707
                if (val == "off" || val == "false")
 
708
                        web_cache = false;
 
709
                else if (val == "on" || val == "true")
 
710
                        web_cache = true;
 
711
                else
 
712
                {
 
713
                        error << "web_cache must be set to on/off or true/false!" << endl;
 
714
                        return -1;
 
715
                }
 
716
        }
 
717
        else if (key == "hide_email")
 
718
        {
 
719
                if (lc != "")
 
720
                {
 
721
                        error << "hide_email cannot be localized" << endl;
 
722
                        return -1;
 
723
                }
 
724
                if (val == "off" || val == "false")
 
725
                        hide_email = false;
 
726
                else if (val == "on" || val == "true")
 
727
                        hide_email = true;
 
728
                else
 
729
                {
 
730
                        error << "hide_email must be set to on/off or true/false!" << endl;
 
731
                        return -1;
 
732
                }
 
733
        }
 
734
        else if (key == "regroupable")
 
735
        {
 
736
                if (lc != "")
 
737
                {
 
738
                        error << "regroupable cannot be localized" << endl;
 
739
                        return -1;
 
740
                }
 
741
                if (val == "off" || val == "false")
 
742
                        regroupable = false;
 
743
                else if (val == "on" || val == "true")
 
744
                        regroupable = true;
 
745
                else
 
746
                {
 
747
                        error << "regroupable must be set to on/off or true/false!" << endl;
 
748
                        return -1;
 
749
                }
 
750
        }
 
751
        else if (key == "raw_email")
 
752
        {
 
753
                if (lc != "")
 
754
                {
 
755
                        error << "raw_email cannot be localized" << endl;
 
756
                        return -1;
 
757
                }
 
758
                if (val == "off" || val == "false")
 
759
                        raw_email = false;
 
760
                else if (val == "on" || val == "true")
 
761
                        raw_email = true;
 
762
                else
 
763
                {
 
764
                        error << "raw_email must be set to on/off or true/false!" << endl;
 
765
                        return -1;
 
766
                }
 
767
        }
 
768
        else if (key == "include")
 
769
        {
 
770
                if (lc != "")
 
771
                {
 
772
                        error << "include cannot be localized" << endl;
 
773
                        return -1;
 
774
                }
 
775
                string file;
 
776
                
 
777
                if (val[0] == '/')
 
778
                        file = val;
 
779
                else    file = dir + val;
 
780
                
 
781
                if (load(file, false) != 0)
 
782
                        return -1;
 
783
        }
 
784
        else
 
785
        {
 
786
                error << "Unknown configuration directive '" << key << "'!" << endl;
 
787
                return -1;
 
788
        }
 
789
        
 
790
        if (val.length() > len)
 
791
        {
 
792
                error << "Value '" << val << "' is too long for directive '" << key << "'!" << endl;
 
793
                return -1;
 
794
        }
 
795
        
 
796
        return 0;
 
797
}
 
798
 
 
799
ostream& operator << (ostream& o, const List::SerializeMagic& lm)
 
800
{
 
801
        const List& m = lm.m;
 
802
        const string& l = lm.l;
 
803
        
 
804
        o << "<list>"
 
805
          << "<id>" << m.mbox << "</id>"
 
806
          << "<group>" << m.group << "</group>"
 
807
          << "<language>" << m.language << "</language>";
 
808
        
 
809
        if (m.offline)
 
810
                o << "<offline/>";
 
811
        
 
812
        if (m.link.is_set())
 
813
                o << "<link>" << xmlEscape << m.link(l) << "</link>";
 
814
                
 
815
        if (m.description.is_set())
 
816
                o << "<description>" << xmlEscape << m.description(l) << "</description>";
 
817
        
 
818
        o  << "<email";
 
819
        if (m.address.length() > 0)
 
820
                o << " address=\"" << xmlEscape << m.address << "\"";
 
821
        if (m.title.is_set())
 
822
                o << " name=\"" << xmlEscape << m.title(l) << "\"";
 
823
        else
 
824
                o << " name=\"" << m.mbox << "\"";
 
825
        
 
826
        o << "/></list>";
 
827
        
 
828
        return o;
 
829
}
 
830
 
 
831
ostream& operator << (ostream& o, const Config::SerializeMagic& cm)
 
832
{
 
833
        const Config& c = cm.c;
 
834
        const string& l = cm.l;
 
835
        
 
836
        // expire = time(0) + 60*5; // 5 minute cache
 
837
        //
 
838
        // tm = gmtime(&expire);
 
839
        // strftime(&timebuf[0], sizeof(timebuf),
 
840
        //      "%a, %d %b %Y %H:%M:%S GMT", tm);
 
841
        
 
842
        char year[40];
 
843
        time_t end_of_archive = time(0) + 365*24*60*60;
 
844
        strftime(&year[0], sizeof(year), "%Y", gmtime(&end_of_archive));
 
845
        
 
846
        o << "<server>"
 
847
          << "<version>" << VERSION << "</version>"
 
848
          << "<eoa-year>" << year << "</eoa-year>"
 
849
          << "<doc-url>" << c.docUrl << "</doc-url>"
 
850
          << "<cgi-url>" << c.cgiUrl << "</cgi-url>"
 
851
          << "<command>" << c.command << "</command>"
 
852
          << "<options>" << c.options << "</options>";
 
853
        
 
854
        if (c.raw_email) o << "<raw-email/>";
 
855
        
 
856
        o << "<archive>";
 
857
        
 
858
        if (c.archive.is_set())
 
859
                o << xmlEscape << c.archive(l);
 
860
        else    o << "Some Mailing List Archive";
 
861
        
 
862
        o << "</archive><email";
 
863
        if (c.admin_address.length() > 0)
 
864
                o << " address=\"" << xmlEscape << c.admin_address << "\"";
 
865
        if (c.admin_name.is_set())
 
866
                o << " name=\"" << xmlEscape << c.admin_name(l) << "\"";
 
867
        o << "/></server>";
 
868
        
 
869
        return o;
 
870
}