1 #include <stdlib.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include <stdio.h>
5
6 #include "alias.h"
7 #include "variables.h"
8 #include "core.h"
9 #include "mystring.h"
10 #include "moderate.h"
11 #include "liscript.h"
12 #include "fileapi.h"
13 #include "trust.h"
14
15 static const char *_sortorder = NULL;
16 struct list_vars *listdata = NULL;
17 struct var_data **sortedvars = NULL;
18
19 static int count_all_vars();
20 static int var_cmp(const void *e1, const void *e2);
21
22 /* Hash a variable name to a hash bucket */
var_hash(const char * varname)23 int var_hash(const char *varname)
24 {
25 int i, len, val;
26
27 len = strlen(varname);
28 val = 0;
29 for(i = 0; i < len; i++) {
30 val += tolower(varname[i]);
31 }
32 return val % HASHSIZE;
33 }
34
35 /* get the current variable value at a specific level */
get_cur_varval_level(struct var_data * var,int level)36 const char *get_cur_varval_level(struct var_data *var, int level)
37 {
38 if(level == VAR_TEMP) {
39 if(var->temp && (var->flags & VAR_TEMP)) return var->temp;
40 } else if (level == VAR_LIST) {
41 if(var->list && (var->flags & VAR_LIST)) return var->list;
42 } else if (level == VAR_SITE) {
43 if(var->site && (var->flags & VAR_SITE)) return var->site;
44 } else if (level == VAR_GLOBAL) {
45 if(var->global && (var->flags & VAR_GLOBAL)) return var->global;
46 } else {
47 return NULL;
48 }
49 return NULL;
50 }
51
52 /* get the current variable value at a specific level or above */
get_cur_varval_level_default(struct var_data * var,int level)53 const char *get_cur_varval_level_default(struct var_data *var, int level)
54 {
55 switch(level) {
56 case VAR_TEMP:
57 if(var->temp && (var->flags & VAR_TEMP)) return var->temp;
58 case VAR_LIST:
59 if(var->list && (var->flags & VAR_LIST)) return var->list;
60 case VAR_SITE:
61 if(var->site && (var->flags & VAR_SITE)) return var->site;
62 case VAR_GLOBAL:
63 if(var->global && (var->flags & VAR_GLOBAL)) return var->global;
64 default:
65 return var->defval;
66 }
67 }
68
69 /* Get the current value of a variable from it's variable record */
get_cur_varval(struct var_data * var)70 const char *get_cur_varval(struct var_data *var)
71 {
72 if(var->temp && (var->flags & VAR_TEMP)) return var->temp;
73 if(var->list && (var->flags & VAR_LIST)) return var->list;
74 if(var->site && (var->flags & VAR_SITE)) return var->site;
75 if(var->global && (var->flags & VAR_GLOBAL)) return var->global;
76 return var->defval;
77 }
78
79 /* Lookup the variable and return it's record if it exists, else null */
find_var_rec(const char * varname)80 struct var_data *find_var_rec(const char *varname)
81 {
82 const char *alias = lookup_alias(varname);
83 int hash;
84 struct var_data *temp;
85
86 if(!alias)
87 alias = varname;
88
89 hash = var_hash(alias);
90 temp = listdata->bucket[hash];
91
92 while(temp) {
93 if(strcasecmp(temp->name, alias) == 0)
94 return temp;
95 temp = temp->next;
96 }
97 return NULL;
98 }
99
100 /* clean up values on a variable record */
clean_var(const char * varname,int flags)101 void clean_var(const char *varname, int flags)
102 {
103 struct var_data *temp = find_var_rec(varname);
104 const char *varval = NULL;
105
106 if(!temp) {
107 log_printf(9, "clean_var: variable '%s' doesn't exist.\n", varname);
108 return;
109 }
110 if(temp->flags & VAR_LOCKED) {
111 log_printf(1, "clean_var: Attempting to clean locked variable '%s'\n",
112 varname);
113 return;
114 }
115 temp->flags &= ~VAR_NOEXPAND;
116
117 if((flags & VAR_TEMP) && temp->temp) {
118 log_printf(9, "clean_var: cleaning var '%s' (TEMP)\n", temp->name);
119 if(temp->type != VAR_DATA)
120 free(temp->temp);
121 temp->temp = NULL;
122 }
123 if((flags & VAR_LIST) && temp->list) {
124 log_printf(9, "clean_var: cleaning var '%s' (LIST)\n", temp->name);
125 if(temp->type != VAR_DATA)
126 free(temp->list);
127 temp->list = NULL;
128 }
129 if((flags & VAR_SITE) && temp->site) {
130 log_printf(9, "clean_var: cleaning var '%s' (SITE)\n", temp->name);
131 if(temp->type != VAR_DATA)
132 free(temp->site);
133 temp->site = NULL;
134 }
135 if((flags & VAR_GLOBAL) && temp->global) {
136 log_printf(9, "clean_var: cleaning var '%s' (GLOBAL)\n", temp->name);
137 if(temp->type != VAR_DATA)
138 free(temp->global);
139 temp->global = NULL;
140 }
141
142 if(temp->expanded){
143 free(temp->expanded);
144 temp->expanded = NULL;
145 }
146 varval = get_cur_varval(temp);
147 if(!varval || strstr(varval, "<$") == NULL)
148 temp->flags |= VAR_NOEXPAND;
149 }
150
151 /* Wipe all non-protected variables */
wipe_vars(int flags)152 void wipe_vars(int flags)
153 {
154 struct var_data *temp;
155 int i;
156 const char *varval = NULL;
157
158 for(i = 0; i < HASHSIZE; i++) {
159 temp = listdata->bucket[i];
160
161 while(temp) {
162 if(temp->flags & VAR_LOCKED) {
163 log_printf(9, "wipe_vars: skipping locked variable '%s'\n",
164 temp->name);
165 temp = temp->next;
166 continue;
167 }
168 temp->flags &= ~VAR_NOEXPAND;
169
170 if((flags & VAR_TEMP) && temp->temp) {
171 if(temp->type != VAR_DATA)
172 free(temp->temp);
173 temp->temp = NULL;
174 }
175 if((flags & VAR_LIST) && temp->list) {
176 if(temp->type != VAR_DATA)
177 free(temp->list);
178 temp->list = NULL;
179 }
180 if((flags & VAR_SITE) && temp->site) {
181 if(temp->type != VAR_DATA)
182 free(temp->site);
183 temp->site = NULL;
184 }
185 if((flags & VAR_GLOBAL) && temp->global) {
186 if(temp->type != VAR_DATA)
187 free(temp->global);
188 temp->global = NULL;
189 }
190 if(temp->expanded) {
191 free(temp->expanded);
192 temp->expanded = NULL;
193 }
194 varval = get_cur_varval(temp);
195 if(!varval || strstr(varval, "<$") == NULL)
196 temp->flags |= VAR_NOEXPAND;
197 temp = temp->next;
198 }
199 }
200 }
201
202 /* Destroy the variable hash table */
nuke_vars(void)203 void nuke_vars(void)
204 {
205 struct var_data *temp, *temp2;
206 int i;
207
208 for(i = 0; i < HASHSIZE; i++) {
209 temp = listdata->bucket[i];
210
211 while(temp) {
212 if(temp->flags & VAR_LOCKED) {
213 log_printf(9, "nuke_vars: variable '%s' was never unlocked.\n",
214 temp->name);
215 }
216
217 temp2 = temp->next;
218 if(temp->name) free(temp->name);
219 if(temp->description) free(temp->description);
220 if(temp->section) free(temp->section);
221 if(temp->example) free(temp->example);
222 if(temp->defval) free(temp->defval);
223 if(temp->global && temp->type != VAR_DATA) free(temp->global);
224 if(temp->site && temp->type != VAR_DATA) free(temp->site);
225 if(temp->list && temp->type != VAR_DATA) free(temp->list);
226 if(temp->temp && temp->type != VAR_DATA) free(temp->temp);
227 if(temp->expanded) free(temp->expanded);
228 if(temp->choices) free(temp->choices);
229 free(temp);
230 temp = temp2;
231 }
232 listdata->bucket[i] = NULL;
233 }
234 }
235
236 /* register a variables information */
register_var(const char * varname,const char * defval,const char * section,const char * desc,const char * example,enum var_type type,int flags)237 void register_var(const char *varname, const char *defval,
238 const char *section, const char *desc,
239 const char *example, enum var_type type, int flags)
240 {
241 struct var_data *temp = find_var_rec(varname);
242 int hash;
243
244 if(temp) {
245 log_printf(0, "Attempting to reregister variable '%s'\n", varname);
246 return;
247 }
248 if(flags & VAR_LOCKED) {
249 flags &= ~VAR_LOCKED;
250 }
251 if(flags & VAR_NOEXPAND) {
252 flags &= ~VAR_NOEXPAND;
253 }
254
255 hash = var_hash(varname);
256 temp = (struct var_data *)malloc(sizeof(struct var_data));
257 temp->name = strdup(varname);
258 temp->description = NULL;
259 temp->section = NULL;
260 temp->example = NULL;
261 temp->defval= NULL;
262 temp->global = NULL;
263 temp->site = NULL;
264 temp->list = NULL;
265 temp->temp = NULL;
266 temp->expanded = NULL;
267 temp->choices = NULL;
268 temp->type = type;
269 if(desc)
270 temp->description = strdup(desc);
271 if(section)
272 temp->section = strdup(section);
273 if(example)
274 temp->example = strdup(example);
275 if(defval) {
276 /* lets do some validation of the variables */
277 switch (temp->type) {
278 case VAR_DATA:
279 temp->defval = (char *)defval;
280 break;
281 case VAR_CHOICE: {
282 char *deftmp, *delim, *dv;
283 deftmp = strdup(defval);
284 delim = strchr(deftmp, ':');
285 dv = strchr(deftmp, '|');
286 if(delim == NULL || dv == NULL) {
287 log_printf(0, "Choice variable '%s' had no list of choices.\n",
288 varname);
289 if(temp->name) free(temp->name);
290 if(temp->description) free(temp->description);
291 if(temp->section) free(temp->section);
292 if(temp->example) free(temp->example);
293 free(deftmp);
294 free(temp);
295 return;
296 } else {
297 if((*(delim+1) != '|') || (delim[strlen(delim)-1] != '|')) {
298 log_printf(0, "Choice variable '%s' had invalid list of choices.\n",
299 varname);
300 if(temp->name) free(temp->name);
301 if(temp->description) free(temp->description);
302 if(temp->section) free(temp->section);
303 if(temp->example) free(temp->example);
304 free(temp);
305 free(deftmp);
306 return;
307 }
308 temp->choices = strdup(delim+1);
309 if(delim != defval) {
310 *delim = '\0';
311 temp->defval = strdup(defval);
312 }
313 free(deftmp);
314 }
315 break;
316 }
317 case VAR_BOOL:
318 if(atoi(defval) || !strcasecmp(defval, "yes") ||
319 !strcasecmp(defval, "on") || !strcasecmp(defval, "y") ||
320 !strcasecmp(defval, "true")) {
321 temp->defval = strdup("1");
322 } else {
323 temp->defval = strdup("0");
324 }
325 break;
326 case VAR_TIME:
327 if(atoi(defval)) {
328 temp->defval = strdup(defval);
329 } else {
330 char buf[BIG_BUF];
331 time_t now = time(NULL);
332 buffer_printf(buf, sizeof(buf) - 1, "%d", (int)now);
333 temp->defval = strdup(buf);
334 }
335 break;
336 case VAR_INT:
337 if(atoi(defval)) {
338 temp->defval = strdup(defval);
339 } else {
340 temp->defval = strdup("0");
341 }
342 break;
343 case VAR_DURATION:
344 case VAR_STRING:
345 temp->defval = strdup(defval);
346 break;
347 default:
348 /* We should never get here!! */
349 log_printf(0, "Attempt to register var of unknown type '%s'\n",
350 varname);
351 return;
352 }
353 }
354 temp->flags = flags;
355 if(!temp->defval || strstr(temp->defval, "<$") == NULL)
356 temp->flags |= VAR_NOEXPAND;
357 temp->next = listdata->bucket[hash];
358 listdata->bucket[hash] = temp;
359 }
360
361 /* Set a variables value */
set_var(const char * varname,const char * varval,int level)362 void set_var(const char *varname, const char *varval, int level)
363 {
364 struct var_data *listtemp;
365 char *temp = NULL;
366
367 listtemp = find_var_rec(varname);
368 if(!listtemp) {
369 if(!get_bool("global-pass")) {
370 log_printf(0, "set_var: Setting an unknown variable '%s'\n",
371 varname);
372 }
373 return;
374 }
375 if(listtemp->flags & VAR_LOCKED) {
376 if(listtemp->type == VAR_DATA) {
377 log_printf(1, "Attempt to set locked variable '%s' to '%x'\n",
378 varname, varval);
379 } else {
380 log_printf(1, "Attempt to set locked variable '%s' to '%s'\n",
381 varname, varval);
382 }
383 }
384 if((listtemp->flags & VAR_RESTRICTED) && (level & VAR_LIST) &&
385 !(level & VAR_RESTRICTED)) {
386 const char *listname;
387
388 listname = get_var("list");
389
390 if (!listname)
391 return;
392
393 if (!is_trusted(listname))
394 return;
395 }
396
397 if(level & VAR_LOCKED) {
398 level &= ~VAR_LOCKED;
399 }
400 if(level & VAR_INTERNAL) {
401 level &= ~VAR_INTERNAL;
402 }
403 if(level & VAR_NOEXPAND) {
404 level &= ~VAR_NOEXPAND;
405 }
406 if(level & VAR_RESTRICTED) {
407 level &= ~VAR_RESTRICTED;
408 }
409
410 if((listtemp->flags & level) == 0) {
411 log_printf(0, "set_var: Variable '%s' illegal at level %d\n", varname,
412 level);
413 return;
414 }
415
416 listtemp->flags &= ~VAR_NOEXPAND;
417
418 /* lets do some validation of the variables */
419 switch (listtemp->type) {
420 case VAR_DATA:
421 temp = (char *)varval;
422 break;
423 case VAR_CHOICE: {
424 char buf[BIG_BUF];
425 buffer_printf(buf, sizeof(buf) - 1, "|%s|", varval);
426 if(strstr(listtemp->choices, buf) == NULL) {
427 log_printf(0, "Attempt to set invalid value for choice variable '%s'\n", varname);
428 return;
429 }
430 temp = strdup(varval);
431 break;
432 }
433 case VAR_BOOL:
434 if(varval) {
435 if(atoi(varval) || !strcasecmp(varval, "yes") ||
436 !strcasecmp(varval, "on") || !strcasecmp(varval, "y") ||
437 !strcasecmp(varval, "true")) {
438 temp = strdup("1");
439 } else {
440 temp = strdup("0");
441 }
442 }
443 break;
444 case VAR_TIME:
445 if(varval && atoi(varval)) {
446 temp = strdup(varval);
447 } else {
448 char buf[BIG_BUF];
449 time_t now = time(NULL);
450 buffer_printf(buf, sizeof(buf) - 1, "%d", (int)now);
451 temp = strdup(buf);
452 }
453 break;
454 case VAR_INT:
455 if(varval && atoi(varval)) {
456 temp = strdup(varval);
457 } else {
458 temp = strdup("0");
459 }
460 break;
461 case VAR_DURATION:
462 case VAR_STRING:
463 if(varval)
464 temp = strdup(varval);
465 break;
466 default:
467 /* We should never get here!! */
468 log_printf(0, "Attempt to set a variable of unknown type '%s'\n",
469 varname);
470 return;
471 }
472
473 switch (level) {
474 case VAR_GLOBAL:
475 if(listtemp->global && listtemp->type != VAR_DATA)
476 free(listtemp->global);
477 listtemp->global = temp;
478 break;
479 case VAR_SITE:
480 if(listtemp->site && listtemp->type != VAR_DATA)
481 free(listtemp->site);
482 listtemp->site = temp;
483 break;
484 case VAR_LIST:
485 if(listtemp->list && listtemp->type != VAR_DATA)
486 free(listtemp->list);
487 listtemp->list = temp;
488 break;
489 case VAR_TEMP:
490 if(listtemp->temp && listtemp->type != VAR_DATA)
491 free(listtemp->temp);
492 listtemp->temp = temp;
493 break;
494 default:
495 log_printf(1, "Attempt to set var '%s' at unknown level %d\n",
496 varname, level);
497 return;
498 }
499 if(listtemp->type == VAR_DATA) {
500 log_printf(9, "Setvar: '%s'='%x' at level %d\n", varname, varval, level);
501 } else {
502 log_printf(9, "Setvar: '%s'='%s' at level %d\n", varname, varval, level);
503 }
504 if(listtemp->expanded) {
505 free(listtemp->expanded);
506 listtemp->expanded = NULL;
507 }
508 temp = (char *)get_cur_varval(listtemp);
509 if(!temp || strstr(temp, "<$") == NULL)
510 listtemp->flags |= VAR_NOEXPAND;
511 }
512
513 /* Return the variable as a data_type */
get_data(const char * varname)514 const void *get_data(const char *varname)
515 {
516 struct var_data *tmp = find_var_rec(varname);
517
518 if(!tmp) {
519 log_printf(9, "get_data: Query for non-variable '%s'\n", varname);
520 return NULL;
521 }
522 if(tmp->type != VAR_DATA) {
523 log_printf(9, "get_data: Variable '%s' is not type DATA\n", varname);
524 return NULL;
525 }
526 return (void *)get_cur_varval(tmp);
527 }
528
529 /* Return a copy of the variable unexpanded */
530
get_var_unexpanded(const char * varname)531 const char *get_var_unexpanded(const char *varname)
532 {
533 struct var_data *tmp = find_var_rec(varname);
534 const char *c;
535
536 if(!tmp) {
537 log_printf(9, "get_var: Query for non-variable '%s'\n", varname);
538 return NULL;
539 }
540 c = get_cur_varval(tmp);
541 log_printf(19, "Getting %s unexpaned as %s\n", varname, c);
542 return c;
543 }
544
545 /* Return the variable data as a raw pointer */
get_var(const char * varname)546 const char *get_var(const char *varname)
547 {
548 struct var_data *tmp = find_var_rec(varname);
549 const char *c;
550
551 if(!tmp) {
552 log_printf(9, "get_var: Query for non-variable '%s'\n", varname);
553 return NULL;
554 }
555 c = get_cur_varval(tmp);
556 if(c && (tmp->type == VAR_STRING || tmp->type == VAR_CHOICE)) {
557 if((tmp->flags & VAR_NOEXPAND) == 0) {
558 char tbuf[BIG_BUF];
559 liscript_parse_line(c, tbuf, sizeof(tbuf) - 1);
560 if(tmp->expanded) free(tmp->expanded);
561 log_printf(19,"Expanded '%s' -> '%s'\n", c, tbuf);
562 tmp->expanded = strdup(tbuf);
563 c = tmp->expanded;
564 }
565 }
566 return c;
567 }
568
569 /* Convert the raw data to a boolean value and return it */
get_bool(const char * varname)570 int get_bool(const char *varname)
571 {
572 struct var_data *tmp = find_var_rec(varname);
573 const char *c;
574
575 if(!tmp) {
576 log_printf(9, "get_bool: Query for non-variable '%s'\n", varname);
577 return 0;
578 }
579 if(tmp->type != VAR_BOOL) {
580 log_printf(9, "get_bool: Variable '%s' is not of type BOOL\n", varname);
581 }
582
583 c = get_cur_varval(tmp);
584
585 if(!c)
586 return 0;
587
588 return atoi(c);
589 }
590
591 /* Convert the raw data to an integer and return it */
get_number(const char * varname)592 int get_number(const char *varname)
593 {
594 struct var_data *tmp = find_var_rec(varname);
595 const char *c;
596
597 if(!tmp) {
598 log_printf(9, "get_number: Query for non-variable '%s'\n", varname);
599 return 0;
600 }
601 if(tmp->type != VAR_INT && tmp->type != VAR_TIME) {
602 log_printf(9,"get_number: Variable '%s' is not available as type INT\n",varname);
603 return 0;
604 }
605
606 c = get_cur_varval(tmp);
607 if(tmp->type == VAR_TIME) {
608 if(!c)
609 return (int)time(NULL);
610 return atoi(c);
611 } else {
612 if(!c)
613 return 0;
614 return atoi(c);
615 }
616 }
617
618 /* Return the raw value as a string, NULL is the empty string */
get_string(const char * varname)619 const char *get_string(const char *varname)
620 {
621 struct var_data *tmp = find_var_rec(varname);
622 const char *c;
623 /* used if we are asked for the string value of a null VAR_TIME var */
624 static char datebuf[BIG_BUF];
625
626 if(!tmp) {
627 log_printf(9, "get_string: Query for non-variable '%s'\n", varname);
628 return "";
629 }
630 if((tmp->type != VAR_STRING) && (tmp->type != VAR_TIME) &&
631 (tmp->type != VAR_DURATION) && (tmp->type != VAR_CHOICE)) {
632 log_printf(9, "get_string: Variable '%s' is not available as type STRING\n",
633 varname);
634 return "";
635 }
636
637 c = get_cur_varval(tmp);
638 if(tmp->type == VAR_TIME) {
639 if(!c) {
640 time_t now = time(NULL);
641 get_date(datebuf, sizeof(datebuf), now);
642 return &datebuf[0];
643 } else {
644 get_date(datebuf, sizeof(datebuf), atoi(c));
645 return &datebuf[0];
646 }
647 } else {
648 if(!c)
649 return "";
650 if(tmp->flags & VAR_NOEXPAND) {
651 return c;
652 } else {
653 char tbuf[BIG_BUF];
654 liscript_parse_line(c, tbuf, sizeof(tbuf) - 1);
655 if(tmp->expanded) free(tmp->expanded);
656 log_printf(19,"Expanded '%s' -> '%s'\n", c, tbuf);
657 tmp->expanded = strdup(tbuf);
658 return tmp->expanded;
659 }
660 }
661 return "";
662 }
663
664 /* Parse the string for a date format and return it as a number of seconds */
get_seconds(const char * varname)665 int get_seconds(const char *varname)
666 {
667 struct var_data *tmp = find_var_rec(varname);
668 const char *c;
669 int res = 0;
670 int total = 0;
671
672 if(!tmp) {
673 log_printf(9, "get_seconds: Query for non-variable '%s'\n", varname);
674 return 0;
675 }
676 if(tmp->type != VAR_DURATION) {
677 log_printf(9, "get_seconds: Variable '%s' is not of type DURATION\n",
678 varname);
679 return 0;
680 }
681
682 c = get_cur_varval(tmp);
683
684 if(!c)
685 return 0;
686 while(*c) {
687 while (*c && isspace((int)(*c))) c++;
688 while (*c && isdigit((int)(*c))) { res = res * 10 + (*c - '0'); c++; }
689 while (*c && isspace((int)(*c))) c++;
690 switch(*c) {
691 case 'd': total += (24 * 60 * 60) * res; c++; break;
692 case 'h': total += (60 * 60) * res; c++; break;
693 case 'm': total += (60) * res; c++; break;
694 default : total += res; c++; break;
695 }
696 }
697 return total;
698 }
699
700 /* Initialize the hash table */
init_vars(void)701 void init_vars(void)
702 {
703 int i;
704 listdata = (struct list_vars *)malloc(sizeof(struct list_vars));
705 for(i = 0; i < HASHSIZE; i++)
706 listdata->bucket[i] = NULL;
707 }
708
709 static int varwalkcount, varwalkmax;
710
start_varlist(void)711 struct var_data *start_varlist(void)
712 {
713 int count, num, i;
714
715 count = count_all_vars();
716
717 sortedvars = (struct var_data **)malloc(sizeof(struct var_data *)*count);
718 if(!sortedvars) {
719 log_printf(0, "Unable to allocate memory for sorting.\n");
720 return NULL;
721 }
722
723 num = 0;
724
725 for (i = 0; i < HASHSIZE; i++) {
726 struct var_data *tmp = listdata->bucket[i];
727 while(tmp) {
728 if(!(tmp->flags & VAR_INTERNAL)) {
729 sortedvars[num++] = tmp;
730 }
731 tmp = tmp->next;
732 }
733 }
734 _sortorder = NULL;
735 qsort(sortedvars, count, sizeof(struct var_data *), var_cmp);
736
737 varwalkcount = 0;
738 varwalkmax = count;
739
740 return(sortedvars[0]);
741 }
742
next_varlist()743 struct var_data *next_varlist ()
744 {
745 if (!sortedvars) return NULL;
746
747 varwalkcount++;
748 if (varwalkcount >= varwalkmax)
749 return NULL;
750
751 return sortedvars[varwalkcount];
752 }
753
finish_varlist(void)754 void finish_varlist(void)
755 {
756 if (!sortedvars) return;
757 varwalkcount = 0; varwalkmax = 0;
758 free(sortedvars);
759 sortedvars = NULL;
760 }
761
lock_var(const char * varname)762 void lock_var(const char *varname)
763 {
764 struct var_data *temp = find_var_rec(varname);
765 if(temp)
766 temp->flags |= VAR_LOCKED;
767 }
768
restrict_var(const char * varname)769 void restrict_var(const char *varname)
770 {
771 struct var_data *temp = find_var_rec(varname);
772 log_printf(8,"restrict_var: %s\n", varname);
773 if(temp)
774 temp->flags |= VAR_RESTRICTED;
775 }
776
unlock_var(const char * varname)777 void unlock_var(const char *varname)
778 {
779 struct var_data *temp = find_var_rec(varname);
780 if(temp)
781 temp->flags &= ~VAR_LOCKED;
782 }
783
count_vars(int level)784 static int count_vars(int level)
785 {
786 int i;
787 int count = 0;
788 int trusted;
789
790 if (level == VAR_LIST) {
791 if (get_var("list"))
792 trusted = is_trusted(get_var("list"));
793 else trusted = 0;
794 } else trusted = 1;
795
796 for (i = 0; i < HASHSIZE; i++) {
797 struct var_data *tmp = listdata->bucket[i];
798 while(tmp) {
799 if((tmp->flags & level) && !(tmp->flags & VAR_INTERNAL)
800 && (!(tmp->flags & VAR_RESTRICTED) || trusted))
801 count++;
802 tmp = tmp->next;
803 }
804 }
805 return count;
806 }
807
count_all_vars()808 static int count_all_vars()
809 {
810 int i;
811 int count = 0;
812 for (i = 0; i < HASHSIZE; i++) {
813 struct var_data *tmp = listdata->bucket[i];
814 while(tmp) {
815 if(!(tmp->flags & VAR_INTERNAL))
816 count++;
817 tmp = tmp->next;
818 }
819 }
820 return count;
821 }
822
823
var_cmp(const void * e1,const void * e2)824 static int var_cmp(const void *e1, const void *e2)
825 {
826 struct var_data *v1, *v2;
827 int cmpval;
828
829 v1 = *(struct var_data **)e1;
830 v2 = *(struct var_data **)e2;
831
832 /* Sanity check! */
833 if (v1->section && !v2->section) return -1;
834 if (v2->section && !v1->section) return 1;
835 if (!v1->section && !v2->section) return 0;
836
837 if(_sortorder) {
838 char *s1, *s2;
839 char buf1[BIG_BUF];
840 char buf2[BIG_BUF];
841 buffer_printf(buf1, sizeof(buf1) - 1, ":%s:", v1->section);
842 buffer_printf(buf2, sizeof(buf2) - 1, ":%s:", v2->section);
843 s1 = strstr(_sortorder, buf1);
844 s2 = strstr(_sortorder, buf2);
845 if(s1 && !s2) return -1;
846 else if(s2 && !s1) return 1;
847 else if(s1 && s2) {
848 if(s1 < s2) return -1;
849 else if(s2 < s1) return 1;
850 else return 0;
851 }
852 }
853
854 cmpval = strcasecmp(v1->section, v2->section);
855
856 if (!cmpval) {
857 cmpval = strcasecmp(v1->name,v2->name);
858 }
859
860 return cmpval;
861 }
862
write_configfile(const char * filename,int level,const char * sortorder)863 void write_configfile(const char *filename, int level, const char *sortorder)
864 {
865 /* Eventually, sortorder will provide a way to sort sections. NYI */
866 FILE *ofile = open_exclusive(filename, "w");
867 int i, trusted;
868 int count = 0, num = 0;
869 struct var_data **arr = NULL;
870 char *lastsection;
871
872 if(!ofile) {
873 log_printf(0, "Unable to open config file '%s' for writing.\n",
874 filename);
875 return;
876 }
877
878 if (level & VAR_LIST) {
879 if (get_var("list"))
880 trusted = is_trusted(get_var("list"));
881 else trusted = 0;
882 } else trusted = 1;
883
884 count = count_vars(level);
885 if(count == 0) {
886 log_printf(0, "No variables to write at level %d.\n", level);
887 close_file(ofile);
888 return;
889 }
890
891 arr = (struct var_data **)malloc(sizeof(struct var_data *)*count);
892 if(!arr) {
893 log_printf(0, "Unable to allocate memory for sorting.\n");
894 close_file(ofile);
895 return;
896 }
897
898 for (i = 0; i < HASHSIZE; i++) {
899 struct var_data *tmp = listdata->bucket[i];
900 while(tmp) {
901 if((tmp->flags & level) && !(tmp->flags & VAR_INTERNAL) &&
902 ((!(tmp->flags & VAR_RESTRICTED)) || trusted)) {
903 arr[num++] = tmp;
904 }
905 tmp = tmp->next;
906 }
907 }
908 _sortorder = sortorder;
909 qsort(arr, count, sizeof(struct var_data *), var_cmp);
910 _sortorder = NULL;
911
912 lastsection = NULL;
913
914 for(i = 0; i < count; i++) {
915 char *desc = arr[i]->description;
916 const char *val;
917 int col = 0;
918
919 if (lastsection) {
920 if(!arr[i]->section) {
921 free(lastsection);
922 lastsection = NULL;
923 write_file(ofile,"\n\n# Miscellaneous Settings\n\n");
924 } else if(strcasecmp(arr[i]->section,lastsection) != 0) {
925 unsigned int counter;
926
927 free(lastsection);
928 lastsection = upperstr(arr[i]->section);
929
930 for (counter = 0; counter < (strlen(lastsection) + 4);
931 counter++) {
932 write_file(ofile,"#");
933 }
934
935 write_file(ofile,"\n# %s #\n", lastsection);
936
937 for (counter = 0; counter < (strlen(lastsection) + 4);
938 counter++) {
939 write_file(ofile,"#");
940 }
941 write_file(ofile,"\n\n");
942 }
943 } else {
944 if (arr[i]->section) {
945 unsigned int counter;
946
947 lastsection = upperstr(arr[i]->section);
948 for (counter = 0; counter < (strlen(lastsection) + 4);
949 counter++) {
950 write_file(ofile,"#");
951 }
952
953 write_file(ofile,"\n# %s #\n", lastsection);
954
955 for (counter = 0; counter < (strlen(lastsection) + 4);
956 counter++) {
957 write_file(ofile,"#");
958 }
959 write_file(ofile,"\n\n");
960 }
961 }
962
963 write_file(ofile, "# %s\n", arr[i]->name);
964
965 while(desc ? *desc : 0) {
966 if(col == 0) {
967 write_file(ofile, "# ");
968 col = 2;
969 }
970 if((*desc == ' ' && col > 65)) {
971 col = 0;
972 write_file(ofile, "\n");
973 } else {
974 write_file(ofile, "%c", *desc);
975 col++;
976 }
977 desc++;
978 }
979 if (arr[i]->example)
980 write_file(ofile, "\n# Example: %s\n", arr[i]->example);
981 write_file(ofile, "#\n");
982 val = get_cur_varval_level(arr[i], level);
983 if(val) {
984 if(arr[i]->type == VAR_CHOICE) {
985 char *z = strchr(val, ':');
986 if(z) *z = '\0';
987 }
988 write_file(ofile, "%s = %s\n\n", arr[i]->name,
989 (arr[i]->type == VAR_BOOL) ?
990 (val ? (*val == '1' ? "true" : "false" ) : "false") :
991 (val ? val : ""));
992 } else {
993 val = get_cur_varval_level_default(arr[i], level);
994 if(arr[i]->type == VAR_CHOICE) {
995 char *z = strchr(val, ':');
996 if(z) *z = '\0';
997 }
998 write_file(ofile, "# %s = %s\n\n", arr[i]->name,
999 (arr[i]->type == VAR_BOOL) ?
1000 (val ? (*val == '1' ? "true" : "false" ) : "false") :
1001 (val ? val : ""));
1002 }
1003 }
1004 close_file(ofile);
1005 }
1006
write_configfile_section(const char * filename,int level,const char * section)1007 void write_configfile_section(const char *filename, int level,
1008 const char *section)
1009 {
1010 FILE *ofile = open_exclusive(filename, "w");
1011 int i;
1012
1013 if(!ofile) {
1014 log_printf(0, "Unable to open config file '%s' for writing.\n",
1015 filename);
1016 return;
1017 }
1018
1019 for (i = 0; i < HASHSIZE; i++) {
1020 struct var_data *tmp = listdata->bucket[i];
1021 while(tmp) {
1022 if((tmp->flags & level) && !(tmp->flags & VAR_INTERNAL)) {
1023 if(strcasecmp(tmp->section, section) == 0) {
1024 char *desc = tmp->description;
1025 const char *val;
1026 int col = 0;
1027 write_file(ofile, "# %s\n", tmp->name);
1028 while(desc ? *desc : 0) {
1029 if(col == 0) {
1030 write_file(ofile, "# ");
1031 col = 2;
1032 }
1033 if((*desc == ' ' && col > 65)) {
1034 col = 0;
1035 write_file(ofile, "\n");
1036 } else {
1037 write_file(ofile, "%c", *desc);
1038 col++;
1039 }
1040 desc++;
1041 }
1042 if (tmp->example)
1043 write_file(ofile, "\n# Example: %s", tmp->example);
1044 write_file(ofile, "#\n");
1045 val = get_cur_varval_level(tmp, level);
1046 if(val)
1047 write_file(ofile, "%s = %s\n\n", tmp->name,
1048 (tmp->type == VAR_BOOL) ?
1049 (val ? (*val == '1' ? "true" : "false" ) : "false") :
1050 (val ? val : ""));
1051 else {
1052 val = get_cur_varval_level_default(tmp, level);
1053 if (val)
1054 write_file(ofile, "# %s = %s\n\n", tmp->name,
1055 (tmp->type == VAR_BOOL) ?
1056 (val ? (*val == '1' ? "true" : "false" ) : "false") :
1057 (val ? val : ""));
1058 else
1059 write_file(ofile, "# %s = \n\n",
1060 tmp->name);
1061 }
1062 }
1063 }
1064 tmp = tmp->next;
1065 }
1066 }
1067 close_file(ofile);
1068 }
1069
1070
init_regvars(void)1071 void init_regvars(void)
1072 {
1073 char buf[BIG_BUF];
1074
1075 /* I'm going to register cookies here too since I don't have any
1076 better place */
1077 register_cookie('M', "modpost-expiration-time", NULL, expire_modpost);
1078
1079 /* and register some variables */
1080 register_var("path", ".", NULL, NULL, NULL, VAR_STRING,
1081 VAR_GLOBAL|VAR_INTERNAL);
1082 register_var("queuefile", NULL, NULL, NULL, NULL, VAR_STRING,
1083 VAR_GLOBAL|VAR_INTERNAL);
1084 register_var("listserver-root", NULL, "Location",
1085 "The path to the root of the Listserver installation",
1086 "listserver-root = /usr/local/listserver", VAR_STRING,
1087 VAR_GLOBAL);
1088 register_alias("listar-root", "listserver-root");
1089 register_alias("sllist-root", "listserver-root");
1090 register_alias("ecartis-root", "listserver-root");
1091 register_var("config-file", "config", "Basic Configuration",
1092 "The name of the list-specific configuration file.",
1093 "config-file = config", VAR_STRING, VAR_GLOBAL|VAR_SITE);
1094 register_var("listserver-modules", NULL, "Location",
1095 "The path to the directory containing the LPM modules.",
1096 "listserver-modules = /usr/local/lists/modules", VAR_STRING,
1097 VAR_GLOBAL);
1098 register_alias("listar-modules", "listserver-modules");
1099 register_alias("sllist-modules", "listserver-modules");
1100 register_alias("ecartis-modules", "listserver-modules");
1101 register_var("listserver-conf", NULL, "Location",
1102 "The path to the listserver configuration files.",
1103 "listserver-conf = /usr/local/mylists/configs",
1104 VAR_STRING, VAR_GLOBAL);
1105 register_alias("listar-conf", "listserver-conf");
1106 register_alias("sllist-conf", "listserver-conf");
1107 register_alias("ecartis-conf", "listserver-conf");
1108 register_var("listserver-data", NULL, "Location",
1109 "The path to the listserver data root.",
1110 "listserver-data = /usr/local/mylists/data",
1111 VAR_STRING, VAR_GLOBAL|VAR_SITE);
1112 register_alias("listar-data", "listserver-data");
1113 register_alias("sllist-data", "listserver-data");
1114 register_alias("ecartis-data", "listserver-data");
1115 register_var("mailserver", "localhost", "SMTP",
1116 "The name of the outging SMTP server to use.",
1117 "mailserver = mail.host1.dom", VAR_STRING,
1118 VAR_GLOBAL|VAR_SITE);
1119 register_var("smtp-errors-file", NULL, NULL, NULL, NULL, VAR_STRING,
1120 VAR_INTERNAL|VAR_GLOBAL);
1121 register_var("form-send-as", NULL, NULL, NULL, NULL, VAR_STRING,
1122 VAR_TEMP|VAR_INTERNAL);
1123 register_var("listserver-admin", "root@localhost", "Addresses",
1124 "The email address of the human in charge of the listserver.",
1125 "listserver-admin = user1@host2.dom", VAR_STRING,
1126 VAR_GLOBAL|VAR_SITE);
1127 register_alias("listar-admin", "listserver-admin");
1128 register_alias("sllist-admin", "listserver-admin");
1129 register_alias("ecartis-admin", "listserver-admin");
1130 register_alias("listar-owner", "listserver-admin");
1131 register_alias("sllist-owner", "listserver-admin");
1132 register_alias("ecartis-owner", "listserver-admin");
1133 register_alias("listserver-owner", "listserver-admin");
1134 register_var("task-expires", "no", NULL, NULL, NULL, VAR_BOOL,
1135 VAR_INTERNAL|VAR_TEMP);
1136 register_var("results-subject-override", NULL, NULL, NULL, NULL,
1137 VAR_STRING, VAR_INTERNAL|VAR_TEMP);
1138 register_var("initial-cmd", NULL, NULL, NULL, NULL,
1139 VAR_STRING, VAR_INTERNAL|VAR_GLOBAL);
1140 register_var("task-form-subject", NULL, NULL, NULL, NULL, VAR_STRING,
1141 VAR_INTERNAL|VAR_TEMP);
1142 register_var("global-pass", "no", NULL, NULL, NULL, VAR_BOOL,
1143 VAR_INTERNAL|VAR_TEMP);
1144 register_var("preserve-queue", "no", "Debugging",
1145 "Controls whether to remove queue file after processing.",
1146 "preserve-queue = yes", VAR_BOOL, VAR_ALL);
1147 register_var("lists-root", "<$listserver-data>/lists", "Location",
1148 "Location of the directory containing all the list info.",
1149 "lists-root = lists", VAR_STRING, VAR_GLOBAL|VAR_SITE);
1150 register_var("mode", "nolist", NULL, NULL, NULL, VAR_STRING,
1151 VAR_TEMP|VAR_GLOBAL|VAR_INTERNAL);
1152 register_var("send-as", NULL, "SMTP",
1153 "Controls what the SMTP return path is set to.",
1154 "send-as = list2-bounce@test2.dom", VAR_STRING, VAR_ALL);
1155 register_var("list-owner", NULL, "Basic Configuration",
1156 "Defines an email address to reach the list owner(s).",
1157 "list-owner = list2-admins@hostname.dom", VAR_STRING, VAR_ALL);
1158 register_var("list", NULL, NULL, NULL, NULL, VAR_STRING,
1159 VAR_INTERNAL|VAR_GLOBAL|VAR_TEMP);
1160 register_var("smtp-last-error", NULL, NULL, NULL, NULL, VAR_STRING,
1161 VAR_INTERNAL|VAR_TEMP);
1162 register_var("listserver-full-name", SERVICE_NAME_MC, "Addresses",
1163 "The friendly name used to identify the listserver.",
1164 "listserver-full-name = List Server",
1165 VAR_STRING, VAR_GLOBAL|VAR_SITE);
1166 register_alias("listar-full-name", "listserver-full-name");
1167 register_alias("sllist-full-name", "listserver-full-name");
1168 register_alias("ecartis-full-name", "listserver-full-name");
1169 register_var("listserver-address", SERVICE_ADDRESS, "Addresses",
1170 "The email address for the listserver control account.",
1171 "listserver-address = listserv@myhost.dom",
1172 VAR_STRING, VAR_GLOBAL|VAR_SITE);
1173 register_alias("listar-address", "listserver-address");
1174 register_alias("sllist-address", "listserver-address");
1175 register_alias("ecartis-address", "listserver-address");
1176 register_var("fakequeue", NULL, NULL, NULL, NULL, VAR_BOOL,
1177 VAR_INTERNAL|VAR_GLOBAL);
1178 register_var("listserver-infile", NULL, NULL, NULL, NULL, VAR_STRING,
1179 VAR_INTERNAL|VAR_GLOBAL);
1180 register_var("cookie-for", NULL, NULL, NULL, NULL, VAR_STRING,
1181 VAR_INTERNAL|VAR_TEMP);
1182 register_var("realsender", NULL, NULL, NULL, NULL, VAR_STRING,
1183 VAR_INTERNAL|VAR_GLOBAL);
1184 register_var("cookie-expiration-time", "1 d", "Timeouts",
1185 "How long until a generated cookie expires.",
1186 "cookie-expiration-time = 3 d 6 h", VAR_DURATION, VAR_ALL);
1187 register_var("modpost-expiration-time", NULL, "Timeouts",
1188 "How long until a moderated post cookie expires.",
1189 "modpost-expiration-time = 2 h", VAR_DURATION, VAR_ALL);
1190 register_var("reply-expires-time", "1 d", "Timeouts",
1191 "How long until an automatic reply expires from the mailbox",
1192 "reply-expires-time = 3 h", VAR_DURATION, VAR_NOLIST);
1193 register_var("form-cc-address", NULL, "SMTP",
1194 "Who should be cc'd on any tasks/forms that the server sends.",
1195 "form-cc-address = user2@host1.dom", VAR_STRING, VAR_ALL);
1196 register_var("form-reply-to", NULL, NULL, NULL, NULL, VAR_STRING,
1197 VAR_INTERNAL|VAR_TEMP);
1198 register_var("task-no-footer", "no", "Basic Configuration",
1199 "Should the messages produced by the server have a footer with version information",
1200 "task-no-footer = yes", VAR_BOOL, VAR_ALL);
1201 register_var("site-config-file", NULL, NULL, NULL, NULL, VAR_STRING,
1202 VAR_GLOBAL|VAR_INTERNAL);
1203 register_var("deny-822-from", "no", "Address Handling",
1204 "Should the RFC822 From: header be trusted for sender.",
1205 "deny-822-from = no", VAR_BOOL, VAR_ALL);
1206 register_var("deny-822-bounce", "no", "Address Handling",
1207 "Should the RFC822 Resent-From: header be trusted for sender.",
1208 "deny-822-bounce = yes", VAR_BOOL, VAR_ALL);
1209 register_var("just-unquoted", "no", NULL, NULL, NULL, VAR_BOOL,
1210 VAR_INTERNAL|VAR_GLOBAL);
1211 register_var("just-unmimed", "no", NULL, NULL, NULL, VAR_BOOL,
1212 VAR_INTERNAL|VAR_GLOBAL);
1213 register_var("unmime-moderate-mode", "no", NULL, NULL, NULL, VAR_BOOL,
1214 VAR_ALL|VAR_INTERNAL);
1215 register_var("resent-from", NULL, NULL, NULL, NULL, VAR_STRING,
1216 VAR_INTERNAL|VAR_GLOBAL);
1217 register_var("jobeoj-wrapper", "no", NULL, NULL, NULL, VAR_BOOL,
1218 VAR_INTERNAL|VAR_GLOBAL);
1219 register_var("ignore-subject-commands", "no", "Basic Configuration",
1220 "Should the server ignore commands in the subject line.",
1221 "ignore-subject-commands = false", VAR_BOOL,
1222 VAR_GLOBAL| VAR_SITE);
1223 register_var("fromaddress", NULL, NULL, NULL, NULL, VAR_STRING,
1224 VAR_INTERNAL|VAR_GLOBAL);
1225 register_var("socket-timeout", "30 s", "Socket IO",
1226 "How long should the server wait on reading a socket.",
1227 "socket-timeout = 5 m", VAR_DURATION, VAR_GLOBAL|VAR_SITE);
1228 register_var("debug", "0", "Debugging", "How much logging should be done.",
1229 "debug = 10", VAR_INT, VAR_ALL);
1230 register_var("cur-parse-line", NULL, NULL, NULL, NULL, VAR_STRING,
1231 VAR_INTERNAL|VAR_GLOBAL);
1232 register_var("approved-address", "<$list>-repost@<$hostname>", "Addresses",
1233 "Address to which approved/rejected/modified moderated posts should be sent.",
1234 "approved-address = mylist-repost@myhost.dom", VAR_STRING,
1235 VAR_ALL);
1236 register_var("moderator", NULL, "Moderation",
1237 "Address for the list moderator(s).",
1238 "moderator = foolist-moderators@hostname.dom", VAR_STRING,
1239 VAR_ALL);
1240 register_var("moderate-notify-nonsub", "no", "Moderation",
1241 "Should posts from non-subscribers be acked if they are moderated.",
1242 "moderate-notify-nonsub = true", VAR_BOOL, VAR_ALL);
1243 register_var("moderate-force-notify", "no", NULL, NULL, NULL,
1244 VAR_BOOL, VAR_TEMP|VAR_INTERNAL);
1245 register_var("moderated-approved-by", NULL, NULL, NULL, NULL,
1246 VAR_STRING, VAR_GLOBAL|VAR_INTERNAL);
1247 register_var("max-rcpt-tries", "5", "SMTP",
1248 "How many times to attempt reading a RCPT TO: response.",
1249 "max-recpt-tries = 3", VAR_INT, VAR_GLOBAL|VAR_SITE);
1250 register_var("sendmail-sleep", "no", "SMTP",
1251 "Should we attempt to sleep a short time between message recipients.",
1252 "sendmail-sleep = on", VAR_BOOL, VAR_GLOBAL|VAR_SITE);
1253 register_var("sendmail-sleep-length", "3 s", "SMTP",
1254 "Override if you need the 'Sendmail Sleeper' option at a different duration than the 3 second default.",
1255 "sendmail-sleep-length = 1 s", VAR_DURATION,
1256 VAR_GLOBAL|VAR_SITE);
1257
1258 register_var("per-user-queuefile", NULL, NULL, NULL, NULL, VAR_STRING,
1259 VAR_INTERNAL|VAR_TEMP);
1260 register_var("per-user-datafile", NULL, NULL, NULL, NULL, VAR_STRING,
1261 VAR_INTERNAL|VAR_TEMP);
1262 register_var("per-user-list", NULL, NULL, NULL, NULL, VAR_STRING,
1263 VAR_INTERNAL|VAR_TEMP);
1264 register_var("per-user-address", NULL, NULL, NULL, NULL, VAR_STRING,
1265 VAR_INTERNAL|VAR_TEMP);
1266 register_var("per-user-data", NULL, NULL, NULL, NULL, VAR_DATA,
1267 VAR_INTERNAL|VAR_TEMP);
1268 register_var("megalist", "no", "ToList",
1269 "Should we process this list on-disk instead of in memory? This disables the receipient list sorting and list-merging functionality of Ecartis, in order to prevent large memory footprint operations. It is useful for lists where the receipient list is too large to effectively do memory-based operations on.",
1270 "megalist = true", VAR_BOOL, VAR_ALL);
1271 register_var("smtp-queue-chunk", NULL, "SMTP",
1272 "Maximum recipients per message submitted to the mail server. Larger lists will be split into chunks of this size.",
1273 "smtp-queue-chunk = 25", VAR_INT, VAR_ALL);
1274 register_var("per-user-modifications", "no", "ToList",
1275 "Do we do per-user processing for list members.",
1276 "per-user-modifications = false", VAR_BOOL, VAR_ALL);
1277 register_var("tolist-send-pause", "0", "ToList",
1278 "How long (in milliseconds) do we sleep between SMTP chunks.",
1279 "tolist-send-pause = 30", VAR_INT, VAR_ALL);
1280 register_var("unmimed-file", "no", NULL, NULL, NULL, VAR_BOOL,
1281 VAR_INTERNAL|VAR_GLOBAL);
1282 register_var("unquoted-file", "no", NULL, NULL, NULL, VAR_BOOL,
1283 VAR_INTERNAL|VAR_GLOBAL);
1284 register_var("unmime-first-level", "no", NULL, NULL, NULL, VAR_BOOL,
1285 VAR_INTERNAL|VAR_TEMP);
1286 register_var("unmime-quiet", "no", "MIME",
1287 "Should the listserver report when it strips MIME attachments.",
1288 "unmime-quiet = no", VAR_BOOL, VAR_ALL);
1289 register_var("validate-users", "no", "Debugging",
1290 "Perform a minimal validation of user@host.dom on all users in the list's user file and log errors.",
1291 "validate-users = true", VAR_BOOL, VAR_ALL);
1292 register_var("no-loose-domain-match", "no", "ToList",
1293 "Should the server treat users of a subdomain as users of the domain for validation purposes.",
1294 "no-loose-domain-match = on", VAR_BOOL, VAR_ALL);
1295 register_var("default-flags", "|ECHOPOST|", "Basic Configuration",
1296 "Default flags given to a user when they are subscribed.",
1297 "default-flags = |NOPOST|DIGEST|", VAR_STRING, VAR_ALL);
1298 register_var("global-blacklist", "banned", "Files",
1299 "Global file containing regular expressions for users who are not allowed to subscribe to lists hosted on this server.",
1300 "global-blacklist = banned", VAR_STRING, VAR_GLOBAL|VAR_SITE);
1301 register_var("logfile", NULL, "Debugging",
1302 "Filename where debugging log information will be stored.",
1303 "logfile = ./server.log", VAR_STRING, VAR_GLOBAL|VAR_SITE);
1304 register_var("full-bounce", "no", "SMTP",
1305 "Should bounces contain the full message or only the headers.",
1306 "full-bounce = false", VAR_BOOL, VAR_ALL);
1307 register_var("error-include-queue", "yes", "Error Handling",
1308 "Should error reports contain the queue associated with that run",
1309 "error-include-queue = yes", VAR_BOOL, VAR_ALL);
1310 register_var("address-failure", "no", NULL, NULL, NULL,
1311 VAR_BOOL, VAR_TEMP|VAR_INTERNAL);
1312 register_var("moderate-quiet","no",NULL,NULL,NULL,
1313 VAR_BOOL, VAR_TEMP|VAR_INTERNAL);
1314 register_var("moderate-include-queue", "no", "Moderation",
1315 "Should moderated messages contain the full message that triggered moderation?",
1316 "moderate-include-queue = yes", VAR_BOOL, VAR_ALL);
1317 register_var("moderate-verbose-subject", "yes", "Moderation",
1318 "Should moderated messages have a more informative subject?",
1319 "moderate-verbose-subject = yes", VAR_BOOL, VAR_ALL);
1320 buffer_printf(buf, sizeof(buf) - 1, "%s.hlp", SERVICE_NAME_LC);
1321 register_var("no-command-file", buf, "Files",
1322 "This is a global file to send if a message to the main listserver or request address has no commands.",
1323 "no-command-file = helpfile",VAR_STRING, VAR_GLOBAL|VAR_SITE);
1324 register_var("submodes-file", "submodes", "Files",
1325 "File containing list specific customized subscription modes.",
1326 "submodes-file = submodes", VAR_STRING, VAR_ALL);
1327 register_var("submodes-mode", NULL, NULL, NULL, NULL, VAR_STRING,
1328 VAR_TEMP|VAR_INTERNAL);
1329 register_var("rabid-mime","no","MIME",
1330 "Should ABSOLUTELY no attachments, EVEN text/plain, be allowed",
1331 "rabid-mime = no",VAR_BOOL,VAR_ALL);
1332 register_var("smtp-socket", "25", "SMTP",
1333 "Which socket should the SMTP server be contacted on.",
1334 "smtp-socket = 26", VAR_INT, VAR_SITE|VAR_GLOBAL);
1335 register_var("cgi-template-dir", "<$listserver-data>/templates",
1336 "CGI", "Directory for CGI gateway templates.",
1337 "cgi-template-dir = <$listserver-data>/templates",
1338 VAR_STRING, VAR_ALL);
1339 register_var("version-file", "<$lists-root>/SITEDATA/version", NULL, NULL,
1340 NULL, VAR_STRING, VAR_GLOBAL|VAR_INTERNAL);
1341 register_var("verbose-moderate-fail", "yes", "Moderation",
1342 "When a moderator approves a message but it is rejected, should the message in question be included in the rejection note?",
1343 "verbose-moderate-fail = yes", VAR_BOOL, VAR_GLOBAL|VAR_SITE|VAR_LIST);
1344
1345 register_var("assume-lists-valid", "no", "Misc",
1346 "Should we assume that all list directories are valid or should we perform checks",
1347 "assume-lists-valid = yes", VAR_BOOL, VAR_GLOBAL|VAR_SITE);
1348 register_var("expire-all-cookies","yes","Cookies",
1349 "Should we expire cookies for all lists on initial run? Should only be set to 'no' on installations with a huge (multi-thousand) number of lists.",
1350 "expire-all-cookies = yes", VAR_BOOL, VAR_GLOBAL|VAR_SITE);
1351 register_var("hooktype", NULL, NULL, NULL, NULL, VAR_STRING, VAR_TEMP|VAR_INTERNAL);
1352 register_var("cheatsheet-file", NULL, NULL, NULL, NULL, VAR_STRING, VAR_TEMP|VAR_INTERNAL);
1353 register_var("stocksend-extra-headers", NULL, NULL, NULL, NULL, VAR_STRING, VAR_TEMP|VAR_INTERNAL);
1354 register_var("form-show-listname", "no", "Misc",
1355 "Should we use the list name (or RFC2369 name) instead of the listserver full name for forms on a per-list basis? (Like admin wrappers and such.)",
1356 "form-show-listname = yes", VAR_BOOL, VAR_GLOBAL|VAR_SITE|VAR_LIST);
1357 register_var("lock-to-user", SERVICE_NAME_LC, "Basic Configuration",
1358 "What is the name of the user whose UID/GID we should lock to if we're run as root?",
1359 "lock-to-user = ecartis", VAR_STRING, VAR_GLOBAL|VAR_INTERNAL);
1360 register_var("liscript-allow-explicit-list", "false", NULL, NULL, NULL,
1361 VAR_BOOL, VAR_TEMP|VAR_INTERNAL);
1362 register_var("pwdfile", "<$lists-root>/SITEDATA/site-passwords",
1363 "Files", "Path to the file containing sitewide passwords (used by web interface and others).",
1364 "pwdfile = SITEDATA/passwd", VAR_STRING, VAR_GLOBAL|VAR_INTERNAL);
1365 register_var("hostname", NULL, "Basic Configuration",
1366 "Hostname for URLs/addresses/headers",
1367 "hostname = lists.mydomain.com", VAR_STRING,
1368 VAR_GLOBAL|VAR_SITE);
1369
1370 register_var("smtp-blind-blast", "false", "SMTP",
1371 "Should Ecartis perform all SMTP operations without regard for result codes (e.g. trust that it was delivered)? NOT RECOMMENDED.",
1372 "smtp-blind-blast = yes", VAR_BOOL,
1373 VAR_GLOBAL|VAR_SITE);
1374 register_var("smtp-retry-forever", "false", "SMTP",
1375 "Should Ecartis continue to wait for SMTP responses for an infinite amount of time, e.g. never give up? This can negatively impact delivery times.",
1376 "smtp-retry-forever = yes", VAR_BOOL,
1377 VAR_GLOBAL|VAR_SITE);
1378 register_var("headers-charset", NULL, "Global",
1379 "Charset used in headers", "headers-charset = ISO-8859-1",
1380 VAR_STRING, VAR_GLOBAL|VAR_SITE|VAR_LIST|VAR_INTERNAL);
1381 register_var("headers-charset-frombody", NULL, "Global",
1382 "Charset used in body, possibly header", "headers-charset-frombody = ISO-8859-1",
1383 VAR_STRING, VAR_GLOBAL|VAR_SITE|VAR_LIST|VAR_INTERNAL|VAR_TEMP);
1384
1385 register_var("copy-requests-to", NULL, "Misc",
1386 "If set, all user request results will be sent to this address. Useful for debugging.",
1387 "copy-requests-to = <$list>-admins@<$hostname>",
1388 VAR_STRING, VAR_GLOBAL|VAR_SITE|VAR_LIST);
1389 }
1390
check_duration(const char * d)1391 int check_duration(const char *d)
1392 {
1393 if(!d)
1394 return 0;
1395 while(*d) {
1396 while (*d && isspace((int)(*d))) d++;
1397 while (*d && isdigit((int)(*d))) d++;
1398 while (*d && isspace((int)(*d))) d++;
1399 switch(*d) {
1400 case 'd':
1401 case 'h':
1402 case 'm':
1403 case 's':
1404 d++; break;
1405 default:
1406 if(isspace((int)*d)) break;
1407 else return 0;
1408 }
1409 }
1410 return 1;
1411 }
1412
write_cheatsheet(const char * filename,const char * sortorder)1413 void write_cheatsheet(const char *filename, const char *sortorder)
1414 {
1415 /* Eventually, sortorder will provide a way to sort sections. NYI */
1416 FILE *ofile = open_exclusive(filename, "w");
1417 int i;
1418 int count = 0, num = 0;
1419 struct var_data **arr = NULL;
1420 char *lastsection;
1421
1422 log_printf(1, "Writing variable cheatsheet file '%s'\n", filename);
1423
1424 if(!ofile) {
1425 log_printf(0, "Unable to open cheatsheet file '%s' for writing.\n",
1426 filename);
1427 return;
1428 }
1429
1430 count = count_all_vars();
1431
1432 arr = (struct var_data **)malloc(sizeof(struct var_data *)*count);
1433 if(!arr) {
1434 log_printf(0, "Unable to allocate memory for sorting.\n");
1435 close_file(ofile);
1436 return;
1437 }
1438
1439 for (i = 0; i < HASHSIZE; i++) {
1440 struct var_data *tmp = listdata->bucket[i];
1441 while(tmp) {
1442 if(!(tmp->flags & VAR_INTERNAL)) {
1443 arr[num++] = tmp;
1444 }
1445 tmp = tmp->next;
1446 }
1447 }
1448 _sortorder = sortorder;
1449 qsort(arr, count, sizeof(struct var_data *), var_cmp);
1450 _sortorder = NULL;
1451
1452 lastsection = NULL;
1453
1454 write_file(ofile,"<title>%s Variable Reference</title>\n\n",
1455 SERVICE_NAME_MC);
1456
1457 write_file(ofile,"<P><font size=+3>%s %s Variable Reference</font></P>\n\n",
1458 SERVICE_NAME_MC, VER_PRODUCTVERSION_STR);
1459
1460 write_file(ofile,"<P>\n<i><b>Note</b>: The 'valid' field describes the %s config files\n", SERVICE_NAME_MC);
1461 write_file(ofile,"where that variable is valid. 'G' means the global config file, 'V' means\n");
1462 write_file(ofile,"a virtual host configuration file, and 'L' means individual list files.\n</P>\n");
1463
1464 write_file(ofile,"<table border=1 width=100%%>\n");
1465
1466 for(i = 0; i < count; i++) {
1467 char *desc = arr[i]->description;
1468
1469 write_file(ofile,"\t<tr>\n");
1470
1471 if (lastsection) {
1472 if(!arr[i]->section) {
1473 free(lastsection);
1474 lastsection = NULL;
1475 write_file(ofile,"\t\t<td colspan=4><font size=+2>Miscellaneous Settings</font></td>\n\t</tr>\n\t<tr>\n");
1476 write_file(ofile,"\t<tr>\n\t<td><b>Variable</b></td><td><b>Type</b></td><td><b>Valid</b></td><td><b>Description</b></td>\n\t</tr>\n<tr>");
1477 } else if(strcasecmp(arr[i]->section,lastsection) != 0) {
1478 free(lastsection);
1479 lastsection = upperstr(arr[i]->section);
1480
1481 write_file(ofile,"\t\t<td colspan=4><font size=+2>%s</font></td>\n\t</tr>\n\t<tr>\n", lastsection);
1482 write_file(ofile,"\t<tr>\n\t<td><b>Variable</b></td><td><b>Type</b></td><td><b>Valid</b></td><td><b>Description</b></td>\n\t</tr>\n<tr>");
1483 }
1484 } else {
1485 if (arr[i]->section) {
1486 lastsection = upperstr(arr[i]->section);
1487
1488 write_file(ofile,"\t\t<td colspan=4><font size=+2>%s</font></td>\n\t</tr>\n", lastsection);
1489 write_file(ofile,"\t<tr>\n\t<td><b>Variable</b></td><td><b>Type</b></td><td><b>Valid</b></td><td><b>Description</b></td>\n\t</tr>\n<tr>");
1490 }
1491 }
1492
1493 write_file(ofile,"\t\t<td valign=top><b>%s</b></td>\n", arr[i]->name);
1494
1495 write_file(ofile,"\t\t<td valign=top>");
1496 switch (arr[i]->type) {
1497 case VAR_STRING:
1498 write_file(ofile,"string");
1499 break;
1500 case VAR_BOOL:
1501 write_file(ofile,"boolean");
1502 break;
1503 case VAR_INT:
1504 write_file(ofile,"integer");
1505 break;
1506 case VAR_DURATION:
1507 write_file(ofile,"duration");
1508 break;
1509 case VAR_DATA:
1510 write_file(ofile,"data");
1511 break;
1512 case VAR_TIME:
1513 write_file(ofile,"time");
1514 break;
1515 case VAR_CHOICE:
1516 write_file(ofile,"choice");
1517 break;
1518 default:
1519 write_file(ofile,"<i>unknown</i>");
1520 }
1521 write_file(ofile,"</td>\n");
1522
1523 write_file(ofile,"\t\t<td valign=top>\n\t\t\t");
1524
1525 if (arr[i]->flags & VAR_GLOBAL) {
1526 write_file(ofile,"G");
1527 }
1528 if (arr[i]->flags & VAR_SITE) {
1529 write_file(ofile,"V");
1530 }
1531 if (arr[i]->flags & VAR_LIST) {
1532 write_file(ofile,"L");
1533 }
1534
1535 write_file(ofile,"\n\t\t</td>\n\t\t<td>\n\t\t\t");
1536 if (desc) {
1537 write_file(ofile,"<P>");
1538 while(*desc) {
1539 if (*desc == '<')
1540 write_file(ofile,"<");
1541 else if (*desc == '>')
1542 write_file(ofile,">");
1543 else
1544 write_file(ofile,"%c", *desc);
1545
1546 desc++;
1547 }
1548 write_file(ofile,"</P>\n\t\t\t");
1549 } else
1550 write_file(ofile,"<P><i>No description</i></P>\n\t\t\t");
1551
1552 if (arr[i]->example)
1553 write_file(ofile,"Example:<BR> <code>%s</code><BR><BR>\n",
1554 arr[i]->example);
1555
1556 if (arr[i]->defval) {
1557 if (arr[i]->type == VAR_BOOL) {
1558 write_file(ofile,"Default value is <code>%s</code><BR>\n",
1559 atoi(arr[i]->defval) ? "true" : "false");
1560 } else if (arr[i]->type == VAR_CHOICE) {
1561 char tempstr[SMALL_BUF];
1562 char *tempptr;
1563
1564 buffer_printf(tempstr, sizeof(tempstr) - 1, "%s", arr[i]->defval);
1565 tempptr = strchr(tempstr,':');
1566 if (tempptr) *tempptr = 0;
1567
1568 write_file(ofile,"Default value is <code>%s</code><BR>\n",
1569 tempstr);
1570 } else {
1571 write_file(ofile,"Default value is <code>%s</code><BR>\n",
1572 arr[i]->defval);
1573 }
1574 }
1575
1576 write_file(ofile,"\t\t</td>\n\t</tr>\n");
1577 }
1578 write_file(ofile,"</table>\n");
1579 close_file(ofile);
1580 }
1581