1 /*
2  * $LynxId: LYReadCFG.c,v 1.199 2021/06/09 21:49:32 tom Exp $
3  */
4 #ifndef NO_RULES
5 #include <HTRules.h>
6 #else
7 #include <HTUtils.h>
8 #endif
9 #include <HTTP.h>		/* 'reloading' flag */
10 #include <HTFile.h>
11 #include <HTInit.h>
12 #include <UCMap.h>
13 
14 #include <LYUtils.h>
15 #include <GridText.h>
16 #include <LYStrings.h>
17 #include <LYStructs.h>
18 #include <LYGlobalDefs.h>
19 #include <LYCharSets.h>
20 #include <LYCharUtils.h>
21 #include <LYKeymap.h>
22 #include <LYJump.h>
23 #include <LYGetFile.h>
24 #include <LYCgi.h>
25 #include <LYCurses.h>
26 #include <LYBookmark.h>
27 #include <LYCookie.h>
28 #include <LYReadCFG.h>
29 #include <HTAlert.h>
30 #include <LYHistory.h>
31 #include <LYPrettySrc.h>
32 #include <LYrcFile.h>
33 
34 #ifdef DIRED_SUPPORT
35 #include <LYLocal.h>
36 #endif /* DIRED_SUPPORT */
37 
38 #include <LYexit.h>
39 #include <LYLeaks.h>
40 
41 #ifndef DISABLE_NEWS
42 #include <HTNews.h>
43 #endif
44 
45 BOOLEAN have_read_cfg = FALSE;
46 BOOLEAN LYUseNoviceLineTwo = TRUE;
47 
48 /*
49  * Translate a TRUE/FALSE field in a string buffer.
50  */
is_true(const char * string)51 static BOOL is_true(const char *string)
52 {
53     if (!strcasecomp(string, "TRUE") || !strcasecomp(string, "ON"))
54 	return (TRUE);
55     else
56 	return (FALSE);
57 }
58 
59 /*
60  * Find an unescaped colon in a string buffer.
61  */
find_colon(const char * buffer)62 static const char *find_colon(const char *buffer)
63 {
64     char ch;
65     const char *buf = buffer;
66 
67     if (buf == NULL)
68 	return NULL;
69 
70     while ((ch = *buf) != 0) {
71 	if (ch == ':')
72 	    return buf;
73 	if (ch == '\\') {
74 	    buf++;
75 	    if (*buf == 0)
76 		break;
77 	}
78 	buf++;
79     }
80     return NULL;
81 }
82 
free_item_list_item(lynx_list_item_type ** list,lynx_list_item_type * ptr)83 static void free_item_list_item(lynx_list_item_type **list,
84 				lynx_list_item_type *ptr)
85 {
86     lynx_list_item_type *prev;
87     lynx_list_item_type *cur;
88 
89     for (cur = *list, prev = 0; cur != 0; prev = cur, cur = cur->next) {
90 	if (cur == ptr) {
91 
92 	    if (prev != 0)
93 		prev->next = cur->next;
94 	    else
95 		*list = cur->next;
96 
97 	    FREE(cur->name);
98 	    FREE(cur->menu_name);
99 	    FREE(cur->command);
100 	    FREE(cur);
101 	    break;
102 	}
103     }
104 }
105 
free_item_list(lynx_list_item_type ** ptr)106 static void free_item_list(lynx_list_item_type **ptr)
107 {
108     while (*ptr != 0) {
109 	free_item_list_item(ptr, *ptr);
110     }
111 }
112 
113 /*
114  * Function for freeing the DOWNLOADER and UPLOADER menus list.  - FM
115  */
free_all_item_lists(void)116 static void free_all_item_lists(void)
117 {
118     free_item_list(&printers);
119     free_item_list(&downloaders);
120 #ifdef DIRED_SUPPORT
121     free_item_list(&uploaders);
122 #endif /* DIRED_SUPPORT */
123 
124 #ifdef USE_EXTERNALS
125     free_item_list(&externals);
126 #endif /* USE_EXTERNALS */
127 
128     return;
129 }
130 
parse_list_bool(BOOL * target,const char * source)131 static const char *parse_list_bool(BOOL *target, const char *source)
132 {
133     const char *result;
134 
135     source = LYSkipCBlanks(source);
136     result = find_colon(source);
137 
138     if (*source != '\0') {
139 	char temp[20];
140 	size_t len = ((result != 0)
141 		      ? (size_t) (result - source)
142 		      : strlen(source));
143 
144 	if (len > sizeof(temp))
145 	    len = (sizeof(temp) - 1);
146 	LYStrNCpy(temp, source, len);
147 	*target = is_true(temp);
148 	CTRACE2(TRACE_CFG, (tfp, "parse_list_bool(%s) '%d'\n", source, *target));
149     }
150     return result;
151 }
152 
parse_list_int(int * target,const char * source)153 static const char *parse_list_int(int *target, const char *source)
154 {
155     const char *result;
156 
157     source = LYSkipCBlanks(source);
158     result = find_colon(source);
159 
160     if (*source != '\0') {
161 	*target = atoi(source);
162 	CTRACE2(TRACE_CFG, (tfp, "parse_list_int(%s) '%d'\n", source, *target));
163     }
164     return result;
165 }
166 
parse_list_string(char ** target,const char * source)167 static const char *parse_list_string(char **target, const char *source)
168 {
169     const char *result;
170 
171     source = LYSkipCBlanks(source);
172     result = find_colon(source);
173 
174     if (*source != '\0') {
175 	const char *next = ((result == 0)
176 			    ? (source + strlen(source))
177 			    : result);
178 
179 	*target = typecallocn(char, (size_t) (next - source + 1));
180 
181 	if (*target == NULL)
182 	    outofmem(__FILE__, "read_cfg");
183 	LYStrNCpy(*target, source, (next - source));
184 	remove_backslashes(*target);
185 
186 	CTRACE2(TRACE_CFG, (tfp, "parse_list_string(%s) '%s'\n", source, *target));
187     }
188     return result;
189 }
190 
191 /*
192  * Process string buffer fields for DOWNLOADER or UPLOADER
193  *                               or PRINTERS   or EXTERNALS menus
194  */
add_item_to_list(char * buffer,lynx_list_item_type ** list_ptr,int special,int menu_name)195 static void add_item_to_list(char *buffer,
196 			     lynx_list_item_type **list_ptr,
197 			     int special,
198 			     int menu_name)
199 {
200     const char *colon, *last_colon;
201     lynx_list_item_type *cur_item, *prev_item;
202 
203     /*
204      * Check if the XWINDOWS or NON_XWINDOWS keyword is present in the last
205      * field, and act properly when found depending if external environment
206      * $DISPLAY variable is set.
207      */
208     if ((colon = find_colon(buffer)) == 0) {
209 	return;
210     }
211     for (last_colon = colon;
212 	 (colon = find_colon(last_colon + 1)) != 0;
213 	 last_colon = colon) {
214 	;
215     }
216 
217     /*
218      * If colon equals XWINDOWS then only continue
219      * if there is a $DISPLAY variable
220      */
221     if (!strcasecomp(last_colon + 1, "XWINDOWS")) {
222 	if (LYgetXDisplay() == NULL)
223 	    return;
224     }
225     /*
226      * If colon equals NON_XWINDOWS then only continue
227      * if there is no $DISPLAY variable
228      */
229     else if (!strcasecomp(last_colon + 1, "NON_XWINDOWS")) {
230 	if (LYgetXDisplay() != NULL)
231 	    return;
232     }
233 
234     /*
235      * Make a linked list
236      */
237     if (*list_ptr == NULL) {
238 	/*
239 	 * First item.
240 	 */
241 	cur_item = typecalloc(lynx_list_item_type);
242 
243 	if (cur_item == NULL)
244 	    outofmem(__FILE__, "read_cfg");
245 
246 	*list_ptr = cur_item;
247 #ifdef LY_FIND_LEAKS
248 	atexit(free_all_item_lists);
249 #endif
250     } else {
251 	/*
252 	 * Find the last item.
253 	 */
254 	for (prev_item = *list_ptr;
255 	     prev_item->next != NULL;
256 	     prev_item = prev_item->next) ;	/* null body */
257 	cur_item = typecalloc(lynx_list_item_type);
258 
259 	if (cur_item == NULL)
260 	    outofmem(__FILE__, "read_cfg");
261 	else
262 	    prev_item->next = cur_item;
263     }
264     /* fill-in nonzero default values */
265     cur_item->pagelen = 66;
266 
267     /*
268      * Find first unescaped colon and process fields
269      */
270     if (find_colon(buffer) != NULL) {
271 	colon = parse_list_string(&(cur_item->name), buffer);
272 
273 	if (colon && menu_name) {
274 	    colon = parse_list_string(&(cur_item->menu_name), colon + 1);
275 	}
276 	if (colon) {
277 	    colon = parse_list_string(&(cur_item->command), colon + 1);
278 	}
279 	if (colon) {
280 	    colon = parse_list_bool(&(cur_item->always_enabled), colon + 1);
281 	}
282 	if (colon) {
283 	    if (special) {
284 		(void) parse_list_int(&(cur_item->pagelen), colon + 1);
285 	    } else {
286 		(void) parse_list_bool(&(cur_item->override_action), colon + 1);
287 	    }
288 	}
289     }
290 
291     /* ignore empty data */
292     if (cur_item->name == NULL
293 	|| cur_item->command == NULL) {
294 	CTRACE2(TRACE_CFG, (tfp, "ignoring incomplete list_item '%s'\n", buffer));
295 	free_item_list_item(list_ptr, cur_item);
296     } else if (cur_item->menu_name == NULL) {
297 	StrAllocCopy(cur_item->menu_name, cur_item->command);
298     }
299 }
300 
find_item_by_number(lynx_list_item_type * list_ptr,char * number)301 lynx_list_item_type *find_item_by_number(lynx_list_item_type *list_ptr,
302 					 char *number)
303 {
304     int value = atoi(number);
305 
306     while (value-- >= 0 && list_ptr != 0) {
307 	list_ptr = list_ptr->next;
308     }
309     return list_ptr;
310 }
311 
match_item_by_name(lynx_list_item_type * ptr,const char * name,int only_overriders)312 int match_item_by_name(lynx_list_item_type *ptr,
313 		       const char *name,
314 		       int only_overriders)
315 {
316     return
317 	(ptr->command != 0
318 	 && !strncasecomp(ptr->name, name, (int) strlen(ptr->name))
319 	 && (only_overriders ? ptr->override_action : 1));
320 }
321 
322 #if defined(USE_COLOR_STYLE) || defined(USE_COLOR_TABLE)
323 
324 #ifndef COLOR_WHITE
325 #define COLOR_WHITE 7
326 #endif
327 
328 #ifndef COLOR_BLACK
329 #define COLOR_BLACK 0
330 #endif
331 
332 #ifdef USE_DEFAULT_COLORS
333 int default_fg = DEFAULT_COLOR;
334 int default_bg = DEFAULT_COLOR;
335 
336 #else
337 int default_fg = COLOR_WHITE;
338 int default_bg = COLOR_BLACK;
339 #endif
340 
341 static const char *Color_Strings[16] =
342 {
343     "black",
344     "red",
345     "green",
346     "brown",
347     "blue",
348     "magenta",
349     "cyan",
350     "lightgray",
351     "gray",
352     "brightred",
353     "brightgreen",
354     "yellow",
355     "brightblue",
356     "brightmagenta",
357     "brightcyan",
358     "white"
359 };
360 
361 #if defined(PDCURSES) && !defined(XCURSES)
362 /*
363  * PDCurses (and possibly some other implementations) use a non-ANSI set of
364  * codes for colors.
365  */
ColorCode(int color)366 static int ColorCode(int color)
367 {
368     /* *INDENT-OFF* */
369     static int map[] =
370     {
371 	0,  4,  2,  6,  1,  5,  3,  7,
372 	8, 12, 10, 14,  9, 13, 11, 15
373     };
374     /* *INDENT-ON* */
375 
376     return map[color];
377 }
378 #else
379 #define ColorCode(color) (color)
380 #endif
381 
382 BOOL default_color_reset = FALSE;
383 
384 /*
385  * Validator for COLOR fields.
386  */
check_color(const char * color,int the_default)387 int check_color(const char *color,
388 		int the_default)
389 {
390     int i;
391 
392     CTRACE2(TRACE_STYLE, (tfp, "check_color(%s,%d)\n", color, the_default));
393     if (!strcasecomp(color, "default")) {
394 #ifdef USE_DEFAULT_COLORS
395 	if (LYuse_default_colors && !default_color_reset)
396 	    the_default = DEFAULT_COLOR;
397 #endif /* USE_DEFAULT_COLORS */
398 	CTRACE2(TRACE_STYLE, (tfp, "=> default %d\n", the_default));
399 	return the_default;
400     }
401     if (!strcasecomp(color, "nocolor"))
402 	return NO_COLOR;
403 
404     for (i = 0; i < 16; i++) {
405 	if (!strcasecomp(color, Color_Strings[i])) {
406 	    int c = ColorCode(i);
407 
408 	    CTRACE2(TRACE_STYLE, (tfp, "=> %d\n", c));
409 	    return c;
410 	}
411     }
412     CTRACE2(TRACE_STYLE, (tfp, "=> ERR_COLOR\n"));
413     return ERR_COLOR;
414 }
415 
lookup_color(int code)416 const char *lookup_color(int code)
417 {
418     unsigned n;
419 
420     for (n = 0; n < 16; n++) {
421 	if ((int) ColorCode(n) == code)
422 	    return Color_Strings[n];
423     }
424     return "default";
425 }
426 #endif /* USE_COLOR_STYLE || USE_COLOR_TABLE */
427 
428 #if defined(USE_COLOR_TABLE) || defined(EXP_ASSUMED_COLOR)
429 
430 /*
431  * Exit routine for failed COLOR parsing.
432  */
exit_with_color_syntax(char * error_line)433 static void exit_with_color_syntax(char *error_line)
434 {
435     unsigned int i;
436 
437     fprintf(stderr, gettext("\
438 Syntax Error parsing COLOR in configuration file:\n\
439 The line must be of the form:\n\
440 COLOR:INTEGER:FOREGROUND:BACKGROUND\n\
441 \n\
442 Here FOREGROUND and BACKGROUND must be one of:\n\
443 The special strings 'nocolor' or 'default', or\n")
444 	);
445     for (i = 0; i < 16; i += 4) {
446 	fprintf(stderr, "%16s %16s %16s %16s\n",
447 		Color_Strings[i], Color_Strings[i + 1],
448 		Color_Strings[i + 2], Color_Strings[i + 3]);
449     }
450     fprintf(stderr, "%s\nCOLOR:%s\n", gettext("Offending line:"), error_line);
451     exit_immediately(EXIT_FAILURE);
452 }
453 #endif /* defined(USE_COLOR_TABLE) || defined(EXP_ASSUMED_COLOR) */
454 
455 #if defined(USE_COLOR_TABLE)
456 /*
457  * Process string buffer fields for COLOR setting.
458  */
parse_color(char * buffer)459 static void parse_color(char *buffer)
460 {
461     int color;
462     const char *fg, *bg;
463     char *temp_fg = 0;
464 
465     /*
466      * We are expecting a line of the form:
467      *    INTEGER:FOREGROUND:BACKGROUND
468      */
469     color = atoi(buffer);
470     if (NULL == (fg = find_colon(buffer)))
471 	exit_with_color_syntax(buffer);
472 
473     if (NULL == (bg = find_colon(++fg)))
474 	exit_with_color_syntax(buffer);
475 
476     StrAllocCopy(temp_fg, fg);
477     temp_fg[bg++ - fg] = '\0';
478 
479 #if defined(USE_SLANG)
480     if ((check_color(temp_fg, default_fg) == ERR_COLOR) ||
481 	(check_color(bg, default_bg) == ERR_COLOR))
482 	exit_with_color_syntax(buffer);
483 
484     SLtt_set_color(color, NULL, temp_fg, bg);
485 #else
486     if (lynx_chg_color(color,
487 		       check_color(temp_fg, default_fg),
488 		       check_color(bg, default_bg)) < 0)
489 	exit_with_color_syntax(buffer);
490 #endif
491     FREE(temp_fg);
492 }
493 #endif /* USE_COLOR_TABLE */
494 /* *INDENT-OFF* */
495 #ifdef USE_SOURCE_CACHE
496 static Config_Enum tbl_source_cache[] = {
497     { "FILE",	SOURCE_CACHE_FILE },
498     { "MEMORY",	SOURCE_CACHE_MEMORY },
499     { "NONE",	SOURCE_CACHE_NONE },
500     { NULL,		-1 },
501 };
502 
503 static Config_Enum tbl_abort_source_cache[] = {
504     { "KEEP",	SOURCE_CACHE_FOR_ABORTED_KEEP },
505     { "DROP",	SOURCE_CACHE_FOR_ABORTED_DROP },
506     { NULL,		-1 },
507 };
508 #endif
509 /* *INDENT-ON* */
510 
511 #define PARSE_ADD(n,v)   {n, CONF_ADD_ITEM,    UNION_ADD(v), 0}
512 #define PARSE_SET(n,v)   {n, CONF_BOOL,        UNION_SET(v), 0}
513 #define PARSE_ENU(n,v,t) {n, CONF_ENUM,        UNION_INT(v), t}
514 #define PARSE_INT(n,v)   {n, CONF_INT,         UNION_INT(v), 0}
515 #define PARSE_TIM(n,v)   {n, CONF_TIME,        UNION_INT(v), 0}
516 #define PARSE_STR(n,v)   {n, CONF_STR,         UNION_STR(v), 0}
517 #define PARSE_PRG(n,v)   {n, CONF_PRG,         UNION_DEF(v), 0}
518 #define PARSE_Env(n,v)   {n, CONF_ENV,         UNION_ENV(v), 0}
519 #define PARSE_ENV(n,v)   {n, CONF_ENV2,        UNION_ENV(v), 0}
520 #define PARSE_FUN(n,v)   {n, CONF_FUN,         UNION_FUN(v), 0}
521 #define PARSE_REQ(n,v)   {n, CONF_INCLUDE,     UNION_FUN(v), 0}
522 #define PARSE_LST(n,v)   {n, CONF_ADD_STRING,  UNION_LST(v), 0}
523 #define PARSE_DEF(n,v)   {n, CONF_ADD_TRUSTED, UNION_DEF(v), 0}
524 #define PARSE_NIL        {NULL, CONF_NIL,      UNION_DEF(0), 0}
525 
526 typedef enum {
527     CONF_NIL = 0
528     ,CONF_BOOL			/* BOOLEAN type */
529     ,CONF_FUN
530     ,CONF_TIME
531     ,CONF_ENUM
532     ,CONF_INT
533     ,CONF_STR
534     ,CONF_PRG
535     ,CONF_ENV			/* from environment variable */
536     ,CONF_ENV2			/* from environment VARIABLE */
537     ,CONF_INCLUDE		/* include file-- handle special */
538     ,CONF_ADD_ITEM
539     ,CONF_ADD_STRING
540     ,CONF_ADD_TRUSTED
541 } Conf_Types;
542 
543 typedef struct {
544     const char *name;
545     Conf_Types type;
546       ParseData;
547     Config_Enum *table;
548 } Config_Type;
549 
assume_charset_fun(char * value)550 static int assume_charset_fun(char *value)
551 {
552     assumed_charset = TRUE;
553     UCLYhndl_for_unspec = safeUCGetLYhndl_byMIME(value);
554     StrAllocCopy(UCAssume_MIMEcharset,
555 		 LYCharSet_UC[UCLYhndl_for_unspec].MIMEname);
556     CTRACE((tfp, "assume_charset_fun %s ->%d ->%s\n",
557 	    NonNull(value),
558 	    UCLYhndl_for_unspec,
559 	    UCAssume_MIMEcharset));
560     return 0;
561 }
562 
assume_local_charset_fun(char * value)563 static int assume_local_charset_fun(char *value)
564 {
565     UCLYhndl_HTFile_for_unspec = safeUCGetLYhndl_byMIME(value);
566     return 0;
567 }
568 
assume_unrec_charset_fun(char * value)569 static int assume_unrec_charset_fun(char *value)
570 {
571     UCLYhndl_for_unrec = safeUCGetLYhndl_byMIME(value);
572     return 0;
573 }
574 
character_set_fun(char * value)575 static int character_set_fun(char *value)
576 {
577     int i = UCGetLYhndl_byAnyName(value);	/* by MIME or full name */
578 
579     if (i < 0) {
580 #ifdef CAN_AUTODETECT_DISPLAY_CHARSET
581 	if (auto_display_charset >= 0
582 	    && (!strncasecomp(value, "AutoDetect ", 11)
583 		|| !strncasecomp(value, "AutoDetect-2 ", 13)))
584 	    current_char_set = auto_display_charset;
585 #endif
586 	/* do nothing here: so fallback to userdefs.h */
587     } else {
588 	current_char_set = i;
589     }
590 
591     return 0;
592 }
593 
outgoing_mail_charset_fun(char * value)594 static int outgoing_mail_charset_fun(char *value)
595 {
596     outgoing_mail_charset = UCGetLYhndl_byMIME(value);
597     /* -1 if NULL or not recognized value: no translation (compatibility) */
598 
599     return 0;
600 }
601 
602 #ifdef EXP_ASSUMED_COLOR
603 /*
604  * Process string buffer fields for ASSUMED_COLOR setting.
605  */
assumed_color_fun(char * buffer)606 static int assumed_color_fun(char *buffer)
607 {
608     const char *fg = buffer, *bg;
609     char *temp_fg = 0;
610 
611     if (LYuse_default_colors) {
612 
613 	/*
614 	 * We are expecting a line of the form:
615 	 *    FOREGROUND:BACKGROUND
616 	 */
617 	if (NULL == (bg = find_colon(fg)))
618 	    exit_with_color_syntax(buffer);
619 
620 	StrAllocCopy(temp_fg, fg);
621 	temp_fg[bg++ - fg] = '\0';
622 
623 	default_fg = check_color(temp_fg, default_fg);
624 	default_bg = check_color(bg, default_bg);
625 
626 	if (default_fg == ERR_COLOR
627 	    || default_bg == ERR_COLOR)
628 	    exit_with_color_syntax(buffer);
629 	FREE(temp_fg);
630     } else {
631 	CTRACE((tfp, "...ignored since DEFAULT_COLORS:off\n"));
632     }
633     return 0;
634 }
635 #endif /* EXP_ASSUMED_COLOR */
636 
637 #ifdef USE_COLOR_TABLE
color_fun(char * value)638 static int color_fun(char *value)
639 {
640     parse_color(value);
641     return 0;
642 }
643 #endif
644 
645 #ifdef USE_COLOR_STYLE
lynx_lss_file_fun(char * value)646 static int lynx_lss_file_fun(char *value)
647 {
648     CTRACE((tfp, "lynx_lss_file_fun '%s'\n", NonNull(value)));
649     if (isEmpty(value)) {
650 	clear_lss_list();
651     } else {
652 	add_to_lss_list(value, NULL);
653     }
654     return 0;
655 }
656 #endif
657 
658 #ifdef USE_DEFAULT_COLORS
update_default_colors(void)659 void update_default_colors(void)
660 {
661     int old_fg = default_fg;
662     int old_bg = default_bg;
663 
664     default_color_reset = !LYuse_default_colors;
665     if (LYuse_default_colors) {
666 	default_color_reset = FALSE;
667 	default_fg = DEFAULT_COLOR;
668 	default_bg = DEFAULT_COLOR;
669     } else {
670 	default_color_reset = TRUE;
671 	default_fg = COLOR_WHITE;
672 	default_bg = COLOR_BLACK;
673     }
674     if (old_fg != default_fg || old_bg != default_bg) {
675 	lynx_setup_colors();
676 #ifdef USE_COLOR_STYLE
677 	update_color_style();
678 #endif
679     }
680 }
681 
default_colors_fun(char * value)682 static int default_colors_fun(char *value)
683 {
684     LYuse_default_colors = is_true(value);
685     update_default_colors();
686     return 0;
687 }
688 #endif
689 
default_bookmark_file_fun(char * value)690 static int default_bookmark_file_fun(char *value)
691 {
692     set_default_bookmark_page(value);
693     return 0;
694 }
695 
default_cache_size_fun(char * value)696 static int default_cache_size_fun(char *value)
697 {
698     HTCacheSize = atoi(value);
699     if (HTCacheSize < 2)
700 	HTCacheSize = 2;
701     return 0;
702 }
703 
default_editor_fun(char * value)704 static int default_editor_fun(char *value)
705 {
706     if (!system_editor)
707 	StrAllocCopy(editor, value);
708     return 0;
709 }
710 
numbers_as_arrows_fun(char * value)711 static int numbers_as_arrows_fun(char *value)
712 {
713     if (is_true(value))
714 	keypad_mode = NUMBERS_AS_ARROWS;
715     else
716 	keypad_mode = LINKS_ARE_NUMBERED;
717 
718     return 0;
719 }
720 
721 #ifdef DIRED_SUPPORT
dired_menu_fun(char * value)722 static int dired_menu_fun(char *value)
723 {
724     add_menu_item(value);
725     return 0;
726 }
727 #endif
728 
jumpfile_fun(char * value)729 static int jumpfile_fun(char *value)
730 {
731     char *buffer = NULL;
732 
733     HTSprintf0(&buffer, "JUMPFILE:%s", value);
734     if (!LYJumpInit(buffer))
735 	CTRACE((tfp, "Failed to register %s\n", buffer));
736     FREE(buffer);
737 
738     return 0;
739 }
740 
741 #ifdef EXP_KEYBOARD_LAYOUT
keyboard_layout_fun(char * key)742 static int keyboard_layout_fun(char *key)
743 {
744     if (!LYSetKbLayout(key))
745 	CTRACE((tfp, "Failed to set keyboard layout %s\n", key));
746     return 0;
747 }
748 #endif /* EXP_KEYBOARD_LAYOUT */
749 
keymap_fun(char * key)750 static int keymap_fun(char *key)
751 {
752     char *func, *efunc;
753 
754     if ((func = StrChr(key, ':')) != NULL) {
755 	*func++ = '\0';
756 	efunc = StrChr(func, ':');
757 	/* Allow comments on the ends of key remapping lines. - DT */
758 	/* Allow third field for line-editor action. - kw */
759 	if (efunc == func) {	/* have 3rd field, but 2nd field empty */
760 	    func = NULL;
761 	} else if (efunc && strncasecomp(efunc + 1, "DIRED", 5) == 0) {
762 	    if (!remap(key, strtok(func, " \t\n:#"), TRUE)) {
763 		fprintf(stderr,
764 			gettext("key remapping of %s to %s for %s failed\n"),
765 			key, func, efunc + 1);
766 	    } else if (!strcmp("TOGGLE_HELP", func)) {
767 		LYUseNoviceLineTwo = FALSE;
768 	    }
769 	    return 0;
770 	} else if (!remap(key, strtok(func, " \t\n:#"), FALSE)) {
771 	    fprintf(stderr, gettext("key remapping of %s to %s failed\n"),
772 		    key, func);
773 	} else {
774 	    if (!strcmp("TOGGLE_HELP", func))
775 		LYUseNoviceLineTwo = FALSE;
776 	}
777 	if (efunc) {
778 	    efunc++;
779 	    if (efunc == strtok((func ? NULL : efunc), " \t\n:#") && *efunc) {
780 		BOOLEAN success = FALSE;
781 		int lkc = lkcstring_to_lkc(key);
782 		int lec = -1;
783 		int select_edi = 0;
784 		char *sselect_edi = strtok(NULL, " \t\n:#");
785 		char **endp = &sselect_edi;
786 
787 		if (sselect_edi) {
788 		    if (*sselect_edi)
789 			select_edi = (int) strtol(sselect_edi, endp, 10);
790 		    if (**endp != '\0') {
791 			fprintf(stderr,
792 				gettext("invalid line-editor selection %s for key %s, selecting all\n"),
793 				sselect_edi, key);
794 			select_edi = 0;
795 		    }
796 		}
797 		/*
798 		 * PASS!  tries to enter the key into the LYLineEditors
799 		 * bindings in a different way from PASS, namely as binding
800 		 * that maps to the specific lynx actioncode (rather than to
801 		 * LYE_FORM_PASS).  That only works for lynx keycodes with
802 		 * modifier bit set, and we have no documented/official way to
803 		 * specify this in the KEYMAP directive, although it can be
804 		 * made to work e.g. by specifying a hex value that has the
805 		 * modifier bit set.  But knowledge about the bit pattern of
806 		 * modifiers should remain in internal matter subject to
807 		 * change...  At any rate, if PASS!  fails try it the same way
808 		 * as for PASS.  - kw
809 		 */
810 		if (!success && strcasecomp(efunc, "PASS!") == 0) {
811 		    if (func) {
812 			lec = LYE_FORM_LAC | lacname_to_lac(func);
813 			success = (BOOL) LYRemapEditBinding(lkc, lec, select_edi);
814 		    }
815 		    if (!success)
816 			fprintf(stderr,
817 				gettext("setting of line-editor binding for key %s (0x%x) to 0x%x for %s failed\n"),
818 				key,
819 				(unsigned) lkc,
820 				(unsigned) lec,
821 				efunc);
822 		    else
823 			return 0;
824 		}
825 		if (!success) {
826 		    lec = lecname_to_lec(efunc);
827 		    success = (BOOL) LYRemapEditBinding(lkc, lec, select_edi);
828 		}
829 		if (!success) {
830 		    if (lec != -1) {
831 			fprintf(stderr,
832 				gettext("setting of line-editor binding for key %s (0x%x) to 0x%x for %s failed\n"),
833 				key,
834 				(unsigned) lkc,
835 				(unsigned) lec,
836 				efunc);
837 		    } else {
838 			fprintf(stderr,
839 				gettext("setting of line-editor binding for key %s (0x%x) for %s failed\n"),
840 				key,
841 				(unsigned) lkc,
842 				efunc);
843 		    }
844 		}
845 	    }
846 	}
847     }
848     return 0;
849 }
850 
localhost_alias_fun(char * value)851 static int localhost_alias_fun(char *value)
852 {
853     LYAddLocalhostAlias(value);
854     return 0;
855 }
856 
857 #ifdef LYNXCGI_LINKS
lynxcgi_environment_fun(char * value)858 static int lynxcgi_environment_fun(char *value)
859 {
860     add_lynxcgi_environment(value);
861     return 0;
862 }
863 #endif
864 
lynx_sig_file_fun(char * value)865 static int lynx_sig_file_fun(char *value)
866 {
867     char temp[LY_MAXPATH];
868 
869     LYStrNCpy(temp, value, sizeof(temp) - 1);
870     if (LYPathOffHomeOK(temp, sizeof(temp))) {
871 	StrAllocCopy(LynxSigFile, temp);
872 	LYAddPathToHome(temp, sizeof(temp), LynxSigFile);
873 	StrAllocCopy(LynxSigFile, temp);
874 	CTRACE((tfp, "LYNX_SIG_FILE set to '%s'\n", LynxSigFile));
875     } else {
876 	CTRACE((tfp, "LYNX_SIG_FILE '%s' is bad. Ignoring.\n", LYNX_SIG_FILE));
877     }
878     return 0;
879 }
880 
881 #ifndef DISABLE_NEWS
news_chunk_size_fun(char * value)882 static int news_chunk_size_fun(char *value)
883 {
884     HTNewsChunkSize = atoi(value);
885     /*
886      * If the new HTNewsChunkSize exceeds the maximum,
887      * increase HTNewsMaxChunk to this size. - FM
888      */
889     if (HTNewsChunkSize > HTNewsMaxChunk)
890 	HTNewsMaxChunk = HTNewsChunkSize;
891     return 0;
892 }
893 
news_max_chunk_fun(char * value)894 static int news_max_chunk_fun(char *value)
895 {
896     HTNewsMaxChunk = atoi(value);
897     /*
898      * If HTNewsChunkSize exceeds the new maximum,
899      * reduce HTNewsChunkSize to this maximum. - FM
900      */
901     if (HTNewsChunkSize > HTNewsMaxChunk)
902 	HTNewsChunkSize = HTNewsMaxChunk;
903     return 0;
904 }
905 
news_posting_fun(char * value)906 static int news_posting_fun(char *value)
907 {
908     LYNewsPosting = is_true(value);
909     no_newspost = (BOOL) (LYNewsPosting == FALSE);
910     return 0;
911 }
912 #endif /* DISABLE_NEWS */
913 
914 #ifndef NO_RULES
cern_rulesfile_fun(char * value)915 static int cern_rulesfile_fun(char *value)
916 {
917     char *rulesfile1 = NULL;
918     char *rulesfile2 = NULL;
919 
920     if (HTLoadRules(value) >= 0) {
921 	return 0;
922     }
923     StrAllocCopy(rulesfile1, value);
924     LYTrimLeading(value);
925     LYTrimTrailing(value);
926 
927     StrAllocCopy(rulesfile2, value);
928     LYTildeExpand(&rulesfile2, FALSE);
929 
930     if (strcmp(rulesfile1, rulesfile2) &&
931 	HTLoadRules(rulesfile2) >= 0) {
932 	FREE(rulesfile1);
933 	FREE(rulesfile2);
934 	return 0;
935     }
936     fprintf(stderr,
937 	    gettext("Lynx: cannot start, CERN rules file %s is not available\n"),
938 	    non_empty(rulesfile2) ? rulesfile2 : gettext("(no name)"));
939     exit_immediately(EXIT_FAILURE);
940     return 0;			/* though redundant, for compiler-warnings */
941 }
942 #endif /* NO_RULES */
943 
referer_with_query_fun(char * value)944 static int referer_with_query_fun(char *value)
945 {
946     if (!strncasecomp(value, "SEND", 4))
947 	LYRefererWithQuery = 'S';
948     else if (!strncasecomp(value, "PARTIAL", 7))
949 	LYRefererWithQuery = 'P';
950     else
951 	LYRefererWithQuery = 'D';
952     return 0;
953 }
954 
status_buffer_size_fun(char * value)955 static int status_buffer_size_fun(char *value)
956 {
957     status_buf_size = atoi(value);
958     if (status_buf_size < 2)
959 	status_buf_size = 2;
960     return 0;
961 }
962 
startfile_fun(char * value)963 static int startfile_fun(char *value)
964 {
965     StrAllocCopy(startfile, value);
966 
967 #ifdef USE_PROGRAM_DIR
968     if (is_url(startfile) == 0) {
969 	char *tmp = NULL;
970 
971 	HTSprintf0(&tmp, "%s\\%s", program_dir, startfile);
972 	FREE(startfile);
973 	LYLocalFileToURL(&startfile, tmp);
974 	FREE(tmp);
975     }
976 #endif
977     return 0;
978 }
979 
suffix_fun(char * value)980 static int suffix_fun(char *value)
981 {
982     char *mime_type, *p, *parsed;
983     const char *encoding = NULL;
984     char *sq = NULL;
985     char *description = NULL;
986     double q = 1.0;
987 
988     if ((strlen(value) < 3)
989 	|| (NULL == (mime_type = StrChr(value, ':')))) {
990 	CTRACE((tfp, "Invalid SUFFIX:%s ignored.\n", value));
991 	return 0;
992     }
993 
994     *mime_type++ = '\0';
995     if (*mime_type) {
996 	if ((parsed = StrChr(mime_type, ':')) != NULL) {
997 	    *parsed++ = '\0';
998 	    if ((sq = StrChr(parsed, ':')) != NULL) {
999 		*sq++ = '\0';
1000 		if ((description = StrChr(sq, ':')) != NULL) {
1001 		    *description++ = '\0';
1002 		    if ((p = StrChr(sq, ':')) != NULL)
1003 			*p = '\0';
1004 		    LYTrimTail(description);
1005 		}
1006 		LYRemoveBlanks(sq);
1007 		if (!*sq)
1008 		    sq = NULL;
1009 	    }
1010 	    LYRemoveBlanks(parsed);
1011 	    LYLowerCase(parsed);
1012 	    if (!*parsed)
1013 		parsed = NULL;
1014 	}
1015 	encoding = parsed;
1016     }
1017 
1018     LYRemoveBlanks(mime_type);
1019     /*
1020      * mime-type is not converted to lowercase on input, to make it possible to
1021      * reproduce the equivalent of some of the HTInit.c defaults that use mixed
1022      * case, although that is not recommended.  - kw
1023      */
1024     if (!*mime_type) {		/* that's ok now, with an encoding!  */
1025 	CTRACE((tfp, "SUFFIX:%s without MIME type for %s\n", value,
1026 		encoding ? encoding : "what?"));
1027 	mime_type = NULL;	/* that's ok now, with an encoding!  */
1028 	if (!encoding)
1029 	    return 0;
1030     }
1031 
1032     if (!encoding) {
1033 	if (strstr(mime_type, "tex") != NULL ||
1034 	    strstr(mime_type, "postscript") != NULL ||
1035 	    strstr(mime_type, "sh") != NULL ||
1036 	    strstr(mime_type, "troff") != NULL ||
1037 	    strstr(mime_type, "rtf") != NULL)
1038 	    encoding = "8bit";
1039 	else
1040 	    encoding = "binary";
1041     }
1042     if (!sq) {
1043 	q = 1.0;
1044     } else {
1045 	double df = strtod(sq, &p);
1046 
1047 	if (p == sq && df <= 0.0) {
1048 	    CTRACE((tfp, "Invalid q=%s for SUFFIX:%s, using -1.0\n",
1049 		    sq, value));
1050 	    q = -1.0;
1051 	} else {
1052 	    q = df;
1053 	}
1054     }
1055     HTSetSuffix5(value, mime_type, encoding, description, q);
1056 
1057     return 0;
1058 }
1059 
suffix_order_fun(char * value)1060 static int suffix_order_fun(char *value)
1061 {
1062     char *p = value;
1063     char *optn;
1064     BOOLEAN want_file_init_now = FALSE;
1065 
1066     LYUseBuiltinSuffixes = TRUE;
1067     while ((optn = HTNextTok(&p, ", ", "", NULL)) != NULL) {
1068 	if (!strcasecomp(optn, "NO_BUILTIN")) {
1069 	    LYUseBuiltinSuffixes = FALSE;
1070 	} else if (!strcasecomp(optn, "PRECEDENCE_HERE")) {
1071 	    want_file_init_now = TRUE;
1072 	} else if (!strcasecomp(optn, "PRECEDENCE_OTHER")) {
1073 	    want_file_init_now = FALSE;
1074 	} else {
1075 	    CTRACE((tfp, "Invalid SUFFIX_ORDER:%s\n", optn));
1076 	    break;
1077 	}
1078     }
1079 
1080     if (want_file_init_now && !FileInitAlreadyDone) {
1081 	HTFileInit();
1082 	FileInitAlreadyDone = TRUE;
1083     }
1084     return 0;
1085 }
1086 
system_editor_fun(char * value)1087 static int system_editor_fun(char *value)
1088 {
1089     StrAllocCopy(editor, value);
1090     system_editor = TRUE;
1091     return 0;
1092 }
1093 
1094 #define SetViewer(mime_type, viewer) \
1095     HTSetPresentation(mime_type, viewer, 0, 1.0, 3.0, 0.0, 0L, mediaCFG)
1096 
viewer_fun(char * value)1097 static int viewer_fun(char *value)
1098 {
1099     char *mime_type;
1100     char *viewer;
1101     char *environment;
1102 
1103     mime_type = value;
1104 
1105     if ((strlen(value) < 3)
1106 	|| (NULL == (viewer = StrChr(mime_type, ':'))))
1107 	return 0;
1108 
1109     *viewer++ = '\0';
1110 
1111     LYRemoveBlanks(mime_type);
1112     LYLowerCase(mime_type);
1113 
1114     environment = strrchr(viewer, ':');
1115     if ((environment != NULL) &&
1116 	(strlen(viewer) > 1) && *(environment - 1) != '\\') {
1117 	*environment++ = '\0';
1118 	remove_backslashes(viewer);
1119 	/*
1120 	 * If environment equals xwindows then only assign the presentation if
1121 	 * there is a $DISPLAY variable.
1122 	 */
1123 	if (!strcasecomp(environment, "XWINDOWS")) {
1124 	    if (LYgetXDisplay() != NULL)
1125 		SetViewer(mime_type, viewer);
1126 	} else if (!strcasecomp(environment, "NON_XWINDOWS")) {
1127 	    if (LYgetXDisplay() == NULL)
1128 		SetViewer(mime_type, viewer);
1129 	} else {
1130 	    SetViewer(mime_type, viewer);
1131 	}
1132     } else {
1133 	remove_backslashes(viewer);
1134 	SetViewer(mime_type, viewer);
1135     }
1136 
1137     return 0;
1138 }
1139 
nonrest_sigwinch_fun(char * value)1140 static int nonrest_sigwinch_fun(char *value)
1141 {
1142     if (!strncasecomp(value, "XWINDOWS", 8)) {
1143 	LYNonRestartingSIGWINCH = (BOOL) (LYgetXDisplay() != NULL);
1144     } else {
1145 	LYNonRestartingSIGWINCH = is_true(value);
1146     }
1147     return 0;
1148 }
1149 
1150 #ifdef USE_CHARSET_CHOICE
matched_charset_choice(int display_charset,int i)1151 static void matched_charset_choice(int display_charset,
1152 				   int i)
1153 {
1154     int j;
1155 
1156     if (display_charset && !custom_display_charset) {
1157 	for (custom_display_charset = TRUE, j = 0; j < LYNumCharsets; ++j)
1158 	    charset_subsets[j].hide_display = TRUE;
1159     } else if (!display_charset && !custom_assumed_doc_charset) {
1160 	for (custom_assumed_doc_charset = TRUE, j = 0; j < LYNumCharsets; ++j)
1161 	    charset_subsets[j].hide_assumed = TRUE;
1162     }
1163     if (display_charset)
1164 	charset_subsets[i].hide_display = FALSE;
1165     else
1166 	charset_subsets[i].hide_assumed = FALSE;
1167 }
1168 
parse_charset_choice(char * p,int display_charset)1169 static int parse_charset_choice(char *p,
1170 				int display_charset)	/*if FALSE, then assumed doc charset */
1171 {
1172     int len, i;
1173     int matches = 0;
1174 
1175     /*only one charset choice is allowed per line! */
1176     LYTrimHead(p);
1177     LYTrimTail(p);
1178     CTRACE((tfp, "parsing charset choice for %s:\"%s\"",
1179 	    (display_charset ? "display charset" : "assumed doc charset"), p));
1180     len = (int) strlen(p);
1181     if (!len) {
1182 	CTRACE((tfp, " - EMPTY STRING\n"));
1183 	return 1;
1184     }
1185     if (*p == '*' && len == 1) {
1186 	if (display_charset)
1187 	    for (custom_display_charset = TRUE, i = 0; i < LYNumCharsets; ++i)
1188 		charset_subsets[i].hide_display = FALSE;
1189 	else
1190 	    for (custom_assumed_doc_charset = TRUE, i = 0; i < LYNumCharsets; ++i)
1191 		charset_subsets[i].hide_assumed = FALSE;
1192 	CTRACE((tfp, " - all unhidden\n"));
1193 	return 0;
1194     }
1195     if (p[len - 1] == '*') {
1196 	--len;
1197 	for (i = 0; i < LYNumCharsets; ++i) {
1198 	    if ((!strncasecomp(p, LYchar_set_names[i], len)) ||
1199 		(!strncasecomp(p, LYCharSet_UC[i].MIMEname, len))) {
1200 		++matches;
1201 		matched_charset_choice(display_charset, i);
1202 	    }
1203 	}
1204 	CTRACE((tfp, " - %d matches\n", matches));
1205 	return 0;
1206     } else {
1207 	for (i = 0; i < LYNumCharsets; ++i) {
1208 	    if ((!strcasecomp(p, LYchar_set_names[i])) ||
1209 		(!strcasecomp(p, LYCharSet_UC[i].MIMEname))) {
1210 		matched_charset_choice(display_charset, i);
1211 		++matches;
1212 		CTRACE((tfp, " - OK, %d matches\n", matches));
1213 		return 0;
1214 	    }
1215 	}
1216 	CTRACE((tfp, " - NOT recognised\n"));
1217 	return 1;
1218     }
1219 }
1220 
parse_display_charset_choice(char * p)1221 static int parse_display_charset_choice(char *p)
1222 {
1223     return parse_charset_choice(p, 1);
1224 }
1225 
parse_assumed_doc_charset_choice(char * p)1226 static int parse_assumed_doc_charset_choice(char *p)
1227 {
1228     return parse_charset_choice(p, 0);
1229 }
1230 
1231 #endif /* USE_CHARSET_CHOICE */
1232 
1233 #ifdef USE_EXTERNALS
1234 /*
1235  * EXTERNAL and EXTERNAL_MENU share the same list.  EXTERNAL_MENU allows
1236  * setting a different name than the command string.
1237  */
external_fun(char * str)1238 static int external_fun(char *str)
1239 {
1240     add_item_to_list(str, &externals, FALSE, TRUE);
1241     return 0;
1242 }
1243 #endif
1244 
1245 #ifdef USE_PRETTYSRC
html_src_bad_syntax(char * value,char * option_name)1246 static void html_src_bad_syntax(char *value,
1247 				char *option_name)
1248 {
1249     char *buf = 0;
1250 
1251     HTSprintf0(&buf, "HTMLSRC_%s", option_name);
1252     LYUpperCase(buf);
1253     fprintf(stderr, "Bad syntax in TAGSPEC %s:%s\n", buf, value);
1254     exit_immediately(EXIT_FAILURE);
1255 }
1256 
parse_html_src_spec(HTlexeme lexeme_code,char * value,char * option_name)1257 static int parse_html_src_spec(HTlexeme lexeme_code, char *value,
1258 			       char *option_name)
1259 {
1260     /* Now checking the value for being correct.  Since HTML_dtd is not
1261      * initialized completely (member tags points to non-initiailized data), we
1262      * use tags_old.  If the syntax is incorrect, then lynx will exit with error
1263      * message.
1264      */
1265     char *ts2;
1266 
1267     if (isEmpty(value))
1268 	return 0;		/* silently ignoring */
1269 
1270 #define BS() html_src_bad_syntax(value,option_name)
1271 
1272     ts2 = StrChr(value, ':');
1273     if (!ts2)
1274 	BS();
1275 
1276     *ts2 = '\0';
1277 
1278     CTRACE2(TRACE_CFG, (tfp,
1279 			"LYReadCFG - parsing tagspec '%s:%s' for option '%s'\n",
1280 			value, ts2, option_name));
1281     html_src_clean_item(lexeme_code);
1282     if (!html_src_parse_tagspec(value, lexeme_code, TRUE, TRUE)
1283 	|| !html_src_parse_tagspec(ts2, lexeme_code, TRUE, TRUE)) {
1284 	*ts2 = ':';
1285 	BS();
1286     }
1287 
1288     *ts2 = ':';
1289     StrAllocCopy(HTL_tagspecs[lexeme_code], value);
1290 #undef BS
1291     return 0;
1292 }
1293 
psrcspec_fun(char * s)1294 static int psrcspec_fun(char *s)
1295 {
1296     char *e;
1297     /* *INDENT-OFF* */
1298     static Config_Enum lexemnames[] =
1299     {
1300 	{ "comm",	HTL_comm	},
1301 	{ "tag",	HTL_tag		},
1302 	{ "attrib",	HTL_attrib	},
1303 	{ "attrval",	HTL_attrval	},
1304 	{ "abracket",	HTL_abracket	},
1305 	{ "entity",	HTL_entity	},
1306 	{ "href",	HTL_href	},
1307 	{ "entire",	HTL_entire	},
1308 	{ "badseq",	HTL_badseq	},
1309 	{ "badtag",	HTL_badtag	},
1310 	{ "badattr",	HTL_badattr	},
1311 	{ "sgmlspecial", HTL_sgmlspecial },
1312 	{ NULL,		-1		}
1313     };
1314     /* *INDENT-ON* */
1315 
1316     int found;
1317 
1318     e = StrChr(s, ':');
1319     if (!e) {
1320 	CTRACE((tfp,
1321 		"bad format of PRETTYSRC_SPEC setting value, ignored %s\n",
1322 		s));
1323 	return 0;
1324     }
1325     *e = '\0';
1326     if (!LYgetEnum(lexemnames, s, &found)) {
1327 	CTRACE((tfp,
1328 		"bad format of PRETTYSRC_SPEC setting value, ignored %s:%s\n",
1329 		s, e + 1));
1330 	return 0;
1331     }
1332     parse_html_src_spec((HTlexeme) found, e + 1, s);
1333     return 0;
1334 }
1335 
read_htmlsrc_attrname_xform(char * str)1336 static int read_htmlsrc_attrname_xform(char *str)
1337 {
1338     int val;
1339 
1340     if (1 == sscanf(str, "%d", &val)) {
1341 	if (val < 0 || val > 2) {
1342 	    CTRACE((tfp,
1343 		    "bad value for htmlsrc_attrname_xform (ignored - must be one of 0,1,2): %d\n",
1344 		    val));
1345 	} else
1346 	    attrname_transform = val;
1347     } else {
1348 	CTRACE((tfp, "bad value for htmlsrc_attrname_xform (ignored): %s\n",
1349 		str));
1350     }
1351     return 0;
1352 }
1353 
read_htmlsrc_tagname_xform(char * str)1354 static int read_htmlsrc_tagname_xform(char *str)
1355 {
1356     int val;
1357 
1358     if (1 == sscanf(str, "%d", &val)) {
1359 	if (val < 0 || val > 2) {
1360 	    CTRACE((tfp,
1361 		    "bad value for htmlsrc_tagname_xform (ignored - must be one of 0,1,2): %d\n",
1362 		    val));
1363 	} else
1364 	    tagname_transform = val;
1365     } else {
1366 	CTRACE((tfp, "bad value for htmlsrc_tagname_xform (ignored): %s\n",
1367 		str));
1368     }
1369     return 0;
1370 }
1371 #endif
1372 
1373 #ifdef USE_SESSIONS
session_limit_fun(char * value)1374 static int session_limit_fun(char *value)
1375 {
1376     session_limit = (short) atoi(value);
1377     if (session_limit < 1)
1378 	session_limit = 1;
1379     else if (session_limit > MAX_SESSIONS)
1380 	session_limit = MAX_SESSIONS;
1381     return 0;
1382 }
1383 #endif /* USE_SESSIONS */
1384 
1385 #if defined(PDCURSES) && defined(PDC_BUILD) && PDC_BUILD >= 2401
screen_size_fun(char * value)1386 static int screen_size_fun(char *value)
1387 {
1388     char *cp;
1389 
1390     if ((cp = StrChr(value, ',')) != 0) {
1391 	*cp++ = '\0';		/* Terminate ID */
1392 	scrsize_x = atoi(value);
1393 	scrsize_y = atoi(cp);
1394 	if ((scrsize_x <= 1) || (scrsize_y <= 1)) {
1395 	    scrsize_x = scrsize_y = 0;
1396 	}
1397 	if ((scrsize_x > 0) && (scrsize_x < 80)) {
1398 	    scrsize_x = 80;
1399 	}
1400 	if ((scrsize_y > 0) && (scrsize_y < 4)) {
1401 	    scrsize_y = 4;
1402 	}
1403 	CTRACE((tfp, "scrsize: x=%d, y=%d\n", scrsize_x, scrsize_y));
1404     }
1405     return 0;
1406 }
1407 #endif
1408 
1409 #if defined(HAVE_LIBINTL_H) || defined(HAVE_LIBGETTEXT_H)
message_language_fun(char * value)1410 static int message_language_fun(char *value)
1411 {
1412     char *tmp = NULL;
1413 
1414     HTSprintf0(&tmp, "LANG=%s", value);
1415     putenv(tmp);
1416 
1417     LYSetTextDomain();
1418 
1419     return 0;
1420 }
1421 #endif
1422 
1423 /* This table is searched ignoring case */
1424 /* *INDENT-OFF* */
1425 static Config_Type Config_Table [] =
1426 {
1427      PARSE_SET(RC_ACCEPT_ALL_COOKIES,   LYAcceptAllCookies),
1428      PARSE_TIM(RC_ALERTSECS,            AlertSecs),
1429 #if USE_BLAT_MAILER
1430      PARSE_SET(RC_ALT_BLAT_MAIL,        mail_is_altblat),
1431 #endif
1432      PARSE_SET(RC_ALWAYS_RESUBMIT_POSTS, LYresubmit_posts),
1433 #ifdef EXEC_LINKS
1434      PARSE_DEF(RC_ALWAYS_TRUSTED_EXEC,  ALWAYS_EXEC_PATH),
1435 #endif
1436      PARSE_FUN(RC_ASSUME_CHARSET,       assume_charset_fun),
1437      PARSE_FUN(RC_ASSUME_LOCAL_CHARSET, assume_local_charset_fun),
1438      PARSE_FUN(RC_ASSUME_UNREC_CHARSET, assume_unrec_charset_fun),
1439 #ifdef EXP_ASSUMED_COLOR
1440      PARSE_FUN(RC_ASSUMED_COLOR,        assumed_color_fun),
1441 #endif
1442 #ifdef USE_CHARSET_CHOICE
1443      PARSE_FUN(RC_ASSUMED_DOC_CHARSET_CHOICE, parse_assumed_doc_charset_choice),
1444 #endif
1445 #ifdef DIRED_SUPPORT
1446      PARSE_INT(RC_AUTO_UNCACHE_DIRLISTS, LYAutoUncacheDirLists),
1447 #endif
1448 #ifndef DISABLE_BIBP
1449      PARSE_STR(RC_BIBP_BIBHOST,         BibP_bibhost),
1450      PARSE_STR(RC_BIBP_GLOBALSERVER,    BibP_globalserver),
1451 #endif
1452 #if USE_BLAT_MAILER
1453      PARSE_SET(RC_BLAT_MAIL,            mail_is_blat),
1454 #endif
1455      PARSE_SET(RC_BLOCK_MULTI_BOOKMARKS, LYMBMBlocked),
1456      PARSE_SET(RC_BOLD_H1,              bold_H1),
1457      PARSE_SET(RC_BOLD_HEADERS,         bold_headers),
1458      PARSE_SET(RC_BOLD_NAME_ANCHORS,    bold_name_anchors),
1459 #ifndef DISABLE_FTP
1460      PARSE_LST(RC_BROKEN_FTP_EPSV,      broken_ftp_epsv),
1461      PARSE_LST(RC_BROKEN_FTP_RETR,      broken_ftp_retr),
1462 #endif
1463      PARSE_PRG(RC_BZIP2_PATH,           ppBZIP2),
1464      PARSE_SET(RC_CASE_SENSITIVE_ALWAYS_ON, LYcase_sensitive),
1465      PARSE_FUN(RC_CHARACTER_SET,        character_set_fun),
1466 #ifdef CAN_SWITCH_DISPLAY_CHARSET
1467      PARSE_STR(RC_CHARSET_SWITCH_RULES, charset_switch_rules),
1468      PARSE_STR(RC_CHARSETS_DIRECTORY,   charsets_directory),
1469 #endif
1470      PARSE_SET(RC_CHECKMAIL,            check_mail),
1471      PARSE_PRG(RC_CHMOD_PATH,           ppCHMOD),
1472      PARSE_SET(RC_COLLAPSE_BR_TAGS,     LYCollapseBRs),
1473 #ifdef USE_COLOR_TABLE
1474      PARSE_FUN(RC_COLOR,                color_fun),
1475 #endif
1476 #ifdef USE_COLOR_STYLE
1477      PARSE_FUN(RC_COLOR_STYLE,          lynx_lss_file_fun),
1478 #endif
1479      PARSE_PRG(RC_COMPRESS_PATH,        ppCOMPRESS),
1480      PARSE_PRG(RC_COPY_PATH,            ppCOPY),
1481      PARSE_INT(RC_CONNECT_TIMEOUT,      connect_timeout),
1482      PARSE_SET(RC_CONV_JISX0201KANA,    conv_jisx0201kana),
1483      PARSE_STR(RC_COOKIE_ACCEPT_DOMAINS, LYCookieSAcceptDomains),
1484 #ifdef USE_PERSISTENT_COOKIES
1485      PARSE_STR(RC_COOKIE_FILE,          LYCookieFile),
1486 #endif /* USE_PERSISTENT_COOKIES */
1487      PARSE_STR(RC_COOKIE_LOOSE_INVALID_DOMAINS, LYCookieSLooseCheckDomains),
1488      PARSE_STR(RC_COOKIE_QUERY_INVALID_DOMAINS, LYCookieSQueryCheckDomains),
1489      PARSE_STR(RC_COOKIE_REJECT_DOMAINS, LYCookieSRejectDomains),
1490 #ifdef USE_PERSISTENT_COOKIES
1491      PARSE_STR(RC_COOKIE_SAVE_FILE,     LYCookieSaveFile),
1492 #endif /* USE_PERSISTENT_COOKIES */
1493      PARSE_STR(RC_COOKIE_STRICT_INVALID_DOMAIN, LYCookieSStrictCheckDomains),
1494      PARSE_ENU(RC_COOKIE_VERSION,       cookie_version, tbl_cookie_version),
1495      PARSE_Env(RC_CSO_PROXY,            0),
1496 #ifdef VMS
1497      PARSE_PRG(RC_CSWING_PATH,          ppCSWING),
1498 #endif
1499      PARSE_TIM(RC_DELAYSECS,            DelaySecs),
1500      PARSE_FUN(RC_DEFAULT_BOOKMARK_FILE, default_bookmark_file_fun),
1501      PARSE_FUN(RC_DEFAULT_CACHE_SIZE,   default_cache_size_fun),
1502 #ifdef USE_DEFAULT_COLORS
1503      PARSE_FUN(RC_DEFAULT_COLORS,       default_colors_fun),
1504 #endif
1505      PARSE_FUN(RC_DEFAULT_EDITOR,       default_editor_fun),
1506      PARSE_STR(RC_DEFAULT_INDEX_FILE,   indexfile),
1507      PARSE_ENU(RC_DEFAULT_KEYPAD_MODE,  keypad_mode, tbl_keypad_mode),
1508      PARSE_FUN(RC_DEFAULT_KEYPAD_MODE_NUMARO, numbers_as_arrows_fun),
1509      PARSE_ENU(RC_DEFAULT_USER_MODE,    user_mode, tbl_user_mode),
1510 #if defined(VMS) && defined(VAXC) && !defined(__DECC)
1511      PARSE_INT(RC_DEFAULT_VIRTUAL_MEMORY_SIZE, HTVirtualMemorySize),
1512 #endif
1513 #ifdef DIRED_SUPPORT
1514      PARSE_FUN(RC_DIRED_MENU,           dired_menu_fun),
1515 #endif
1516 #ifdef USE_CHARSET_CHOICE
1517      PARSE_FUN(RC_DISPLAY_CHARSET_CHOICE, parse_display_charset_choice),
1518 #endif
1519      PARSE_SET(RC_DONT_WRAP_PRE,        dont_wrap_pre),
1520      PARSE_ADD(RC_DOWNLOADER,           downloaders),
1521      PARSE_SET(RC_EMACS_KEYS_ALWAYS_ON, emacs_keys),
1522      PARSE_FUN(RC_ENABLE_LYNXRC,        enable_lynxrc),
1523      PARSE_SET(RC_ENABLE_SCROLLBACK,    enable_scrollback),
1524 #ifdef USE_EXTERNALS
1525      PARSE_ADD(RC_EXTERNAL,             externals),
1526      PARSE_FUN(RC_EXTERNAL_MENU,        external_fun),
1527 #endif
1528      PARSE_Env(RC_FINGER_PROXY,         0),
1529 #if defined(_WINDOWS)	/* 1998/10/05 (Mon) 17:34:15 */
1530      PARSE_SET(RC_FOCUS_WINDOW,         focus_window),
1531 #endif
1532      PARSE_SET(RC_FORCE_8BIT_TOUPPER,   UCForce8bitTOUPPER),
1533      PARSE_ENU(RC_FORCE_COOKIE_PROMPT,  cookie_noprompt, tbl_force_prompt),
1534      PARSE_SET(RC_FORCE_EMPTY_HREFLESS_A, force_empty_hrefless_a),
1535      PARSE_SET(RC_FORCE_HTML,           LYforce_HTML_mode),
1536      PARSE_SET(RC_FORCE_SSL_COOKIES_SECURE, LYForceSSLCookiesSecure),
1537 #ifdef USE_SSL
1538      PARSE_ENU(RC_FORCE_SSL_PROMPT,     ssl_noprompt, tbl_force_prompt),
1539 #endif
1540 #if !defined(NO_OPTION_FORMS) && !defined(NO_OPTION_MENU)
1541      PARSE_SET(RC_FORMS_OPTIONS,        LYUseFormsOptions),
1542 #endif
1543      PARSE_STR(RC_FTP_FORMAT,           ftp_format),
1544 #ifndef DISABLE_FTP
1545      PARSE_SET(RC_FTP_PASSIVE,          ftp_passive),
1546 #endif
1547      PARSE_Env(RC_FTP_PROXY,            0),
1548      PARSE_STR(RC_GLOBAL_EXTENSION_MAP, global_extension_map),
1549      PARSE_STR(RC_GLOBAL_MAILCAP,       global_type_map),
1550      PARSE_Env(RC_GOPHER_PROXY,         0),
1551      PARSE_SET(RC_GOTOBUFFER,           goto_buffer),
1552      PARSE_PRG(RC_GZIP_PATH,            ppGZIP),
1553      PARSE_SET(RC_GUESS_SCHEME,         LYGuessScheme),
1554      PARSE_STR(RC_HELPFILE,             helpfile),
1555      PARSE_FUN(RC_HIDDENLINKS,          hiddenlinks_fun),
1556 #ifdef MARK_HIDDEN_LINKS
1557      PARSE_STR(RC_HIDDEN_LINK_MARKER,   hidden_link_marker),
1558 #endif
1559      PARSE_SET(RC_HISTORICAL_COMMENTS,  historical_comments),
1560      PARSE_SET(RC_HTML5_CHARSETS,       html5_charsets),
1561 #ifdef USE_PRETTYSRC
1562      PARSE_FUN(RC_HTMLSRC_ATTRNAME_XFORM, read_htmlsrc_attrname_xform),
1563      PARSE_FUN(RC_HTMLSRC_TAGNAME_XFORM, read_htmlsrc_tagname_xform),
1564 #endif
1565      PARSE_FUN(RC_HTTP_PROTOCOL,        get_http_protocol),
1566      PARSE_Env(RC_HTTP_PROXY,           0),
1567      PARSE_Env(RC_HTTPS_PROXY,          0),
1568      PARSE_REQ(RC_INCLUDE,              0),
1569      PARSE_PRG(RC_INFLATE_PATH,         ppINFLATE),
1570      PARSE_TIM(RC_INFOSECS,             InfoSecs),
1571      PARSE_PRG(RC_INSTALL_PATH,         ppINSTALL),
1572      PARSE_STR(RC_JUMP_PROMPT,          jumpprompt),
1573      PARSE_SET(RC_JUMPBUFFER,           jump_buffer),
1574      PARSE_FUN(RC_JUMPFILE,             jumpfile_fun),
1575 #ifdef USE_JUSTIFY_ELTS
1576      PARSE_SET(RC_JUSTIFY,              ok_justify),
1577      PARSE_INT(RC_JUSTIFY_MAX_VOID_PERCENT, justify_max_void_percent),
1578 #endif
1579 #ifdef EXP_KEYBOARD_LAYOUT
1580      PARSE_FUN(RC_KEYBOARD_LAYOUT,      keyboard_layout_fun),
1581 #endif
1582      PARSE_FUN(RC_KEYMAP,               keymap_fun),
1583      PARSE_SET(RC_LEFTARROW_IN_TEXTFLD_PROMPT, textfield_prompt_at_left_edge),
1584      PARSE_SET(RC_LISTONLY,             dump_links_only),
1585      PARSE_SET(RC_LIST_DECODED,         dump_links_decoded),
1586 #ifndef VMS
1587      PARSE_STR(RC_LIST_FORMAT,          list_format),
1588 #endif
1589      PARSE_SET(RC_LIST_INLINE,          dump_links_inline),
1590 #ifndef DISABLE_NEWS
1591      PARSE_SET(RC_LIST_NEWS_DATES,      LYListNewsDates),
1592      PARSE_SET(RC_LIST_NEWS_NUMBERS,    LYListNewsNumbers),
1593 #endif
1594 #ifdef USE_LOCALE_CHARSET
1595      PARSE_SET(RC_LOCALE_CHARSET,       LYLocaleCharset),
1596 #endif
1597      PARSE_STR(RC_LOCAL_DOMAIN,         LYLocalDomain),
1598      PARSE_SET(RC_LOCALHOST,            local_host_only),
1599      PARSE_FUN(RC_LOCALHOST_ALIAS,      localhost_alias_fun),
1600 #if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS)
1601      PARSE_SET(RC_LOCAL_EXECUTION_LINKS_ALWAYS, local_exec),
1602      PARSE_SET(RC_LOCAL_EXECUTION_LINKS_LOCAL, local_exec_on_local_files),
1603 #endif
1604      PARSE_STR(RC_LYNX_HOST_NAME,       LYHostName),
1605      PARSE_FUN(RC_LYNX_SIG_FILE,        lynx_sig_file_fun),
1606 #ifdef LYNXCGI_LINKS
1607 #ifndef VMS
1608      PARSE_STR(RC_LYNXCGI_DOCUMENT_ROOT, LYCgiDocumentRoot),
1609 #endif
1610      PARSE_FUN(RC_LYNXCGI_ENVIRONMENT,  lynxcgi_environment_fun),
1611 #endif
1612 #if USE_VMS_MAILER
1613      PARSE_STR(RC_MAIL_ADRS,            mail_adrs),
1614 #endif
1615      PARSE_SET(RC_MAIL_SYSTEM_ERROR_LOGGING, error_logging),
1616      PARSE_SET(RC_MAKE_LINKS_FOR_ALL_IMAGES, clickable_images),
1617      PARSE_SET(RC_MAKE_PSEUDO_ALTS_FOR_INLINES, pseudo_inline_alts),
1618      PARSE_INT(RC_MAX_COOKIES_BUFFER,   max_cookies_buffer),
1619      PARSE_INT(RC_MAX_COOKIES_DOMAIN,   max_cookies_domain),
1620      PARSE_INT(RC_MAX_COOKIES_GLOBAL,   max_cookies_global),
1621      PARSE_INT(RC_MAX_URI_SIZE,         max_uri_size),
1622      PARSE_TIM(RC_MESSAGESECS,          MessageSecs),
1623 #if defined(HAVE_LIBINTL_H) || defined(HAVE_LIBGETTEXT_H)
1624      PARSE_FUN(RC_MESSAGE_LANGUAGE,     message_language_fun),
1625 #endif
1626      PARSE_SET(RC_MINIMAL_COMMENTS,     minimal_comments),
1627      PARSE_PRG(RC_MKDIR_PATH,           ppMKDIR),
1628      PARSE_ENU(RC_MULTI_BOOKMARK_SUPPORT, LYMultiBookmarks, tbl_multi_bookmarks),
1629      PARSE_PRG(RC_MV_PATH,              ppMV),
1630      PARSE_SET(RC_NCR_IN_BOOKMARKS,     UCSaveBookmarksInUnicode),
1631 #ifdef EXP_NESTED_TABLES
1632      PARSE_SET(RC_NESTED_TABLES,        nested_tables),
1633 #endif
1634 #ifndef DISABLE_NEWS
1635      PARSE_FUN(RC_NEWS_CHUNK_SIZE,      news_chunk_size_fun),
1636      PARSE_FUN(RC_NEWS_MAX_CHUNK,       news_max_chunk_fun),
1637      PARSE_FUN(RC_NEWS_POSTING,         news_posting_fun),
1638      PARSE_Env(RC_NEWS_PROXY,           0),
1639      PARSE_Env(RC_NEWSPOST_PROXY,       0),
1640      PARSE_Env(RC_NEWSREPLY_PROXY,      0),
1641      PARSE_Env(RC_NNTP_PROXY,           0),
1642      PARSE_ENV(RC_NNTPSERVER,           0), /* actually NNTPSERVER */
1643 #endif
1644      PARSE_SET(RC_NUMBER_FIELDS_ON_LEFT,number_fields_on_left),
1645      PARSE_SET(RC_NUMBER_LINKS_ON_LEFT, number_links_on_left),
1646      PARSE_SET(RC_NO_DOT_FILES,         no_dotfiles),
1647      PARSE_SET(RC_NO_FILE_REFERER,      no_filereferer),
1648 #ifndef VMS
1649      PARSE_SET(RC_NO_FORCED_CORE_DUMP,  LYNoCore),
1650 #endif
1651      PARSE_SET(RC_NO_FROM_HEADER,       LYNoFromHeader),
1652      PARSE_SET(RC_NO_ISMAP_IF_USEMAP,   LYNoISMAPifUSEMAP),
1653      PARSE_SET(RC_NO_MARGINS,           no_margins),
1654      PARSE_SET(RC_NO_PAUSE,             no_pause),
1655      PARSE_Env(RC_NO_PROXY,             0),
1656      PARSE_SET(RC_NO_REFERER_HEADER,    LYNoRefererHeader),
1657      PARSE_SET(RC_NO_TABLE_CENTER,      no_table_center),
1658      PARSE_SET(RC_NO_TITLE,             no_title),
1659      PARSE_SET(RC_UPDATE_TERM_TITLE,    update_term_title),
1660      PARSE_FUN(RC_NONRESTARTING_SIGWINCH, nonrest_sigwinch_fun),
1661      PARSE_FUN(RC_OUTGOING_MAIL_CHARSET, outgoing_mail_charset_fun),
1662 #ifdef DISP_PARTIAL
1663      PARSE_SET(RC_PARTIAL,              display_partial_flag),
1664      PARSE_INT(RC_PARTIAL_THRES,        partial_threshold),
1665 #endif
1666 #ifdef USE_PERSISTENT_COOKIES
1667      PARSE_SET(RC_PERSISTENT_COOKIES,   persistent_cookies),
1668 #endif /* USE_PERSISTENT_COOKIES */
1669      PARSE_STR(RC_PERSONAL_EXTENSION_MAP, personal_extension_map),
1670      PARSE_STR(RC_PERSONAL_MAILCAP,     personal_type_map),
1671      PARSE_LST(RC_POSITIONABLE_EDITOR,  positionable_editor),
1672      PARSE_STR(RC_PREFERRED_CHARSET,    pref_charset),
1673      PARSE_ENU(RC_PREFERRED_CONTENT_TYPE, LYContentType, tbl_preferred_content),
1674      PARSE_ENU(RC_PREFERRED_ENCODING,   LYAcceptEncoding, tbl_preferred_encoding),
1675      PARSE_STR(RC_PREFERRED_LANGUAGE,   language),
1676      PARSE_ENU(RC_PREFERRED_MEDIA_TYPES, LYAcceptMedia, tbl_preferred_media),
1677      PARSE_SET(RC_PREPEND_BASE_TO_SOURCE, LYPrependBaseToSource),
1678      PARSE_SET(RC_PREPEND_CHARSET_TO_SOURCE, LYPrependCharsetToSource),
1679 #ifdef USE_PRETTYSRC
1680      PARSE_SET(RC_PRETTYSRC,            LYpsrc),
1681      PARSE_FUN(RC_PRETTYSRC_SPEC,       psrcspec_fun),
1682      PARSE_SET(RC_PRETTYSRC_VIEW_NO_ANCHOR_NUM, psrcview_no_anchor_numbering),
1683 #endif
1684      PARSE_ADD(RC_PRINTER,              printers),
1685      PARSE_SET(RC_QUIT_DEFAULT_YES,     LYQuitDefaultYes),
1686      PARSE_INT(RC_READ_TIMEOUT,         reading_timeout),
1687      PARSE_INT(RC_REDIRECTION_LIMIT,    redirection_limit),
1688      PARSE_FUN(RC_REFERER_WITH_QUERY,   referer_with_query_fun),
1689 #ifdef USE_CMD_LOGGING
1690      PARSE_TIM(RC_REPLAYSECS,           ReplaySecs),
1691 #endif
1692      PARSE_SET(RC_REUSE_TEMPFILES,      LYReuseTempfiles),
1693      PARSE_PRG(RC_RLOGIN_PATH,          ppRLOGIN),
1694      PARSE_PRG(RC_RMDIR_PATH,           ppRMDIR),
1695      PARSE_PRG(RC_RM_PATH,              ppRM),
1696 #ifndef NO_RULES
1697      PARSE_FUN(RC_RULE,                 HTSetConfiguration),
1698      PARSE_FUN(RC_RULESFILE,            cern_rulesfile_fun),
1699 #endif /* NO_RULES */
1700      PARSE_STR(RC_SAVE_SPACE,           lynx_save_space),
1701      PARSE_SET(RC_SCAN_FOR_BURIED_NEWS_REFS, scan_for_buried_news_references),
1702 #if defined(PDCURSES) && defined(PDC_BUILD) && PDC_BUILD >= 2401
1703      PARSE_FUN(RC_SCREEN_SIZE,          screen_size_fun),
1704 #endif
1705 #ifdef USE_SCROLLBAR
1706      PARSE_SET(RC_SCROLLBAR,            LYShowScrollbar),
1707      PARSE_SET(RC_SCROLLBAR_ARROW,      LYsb_arrow),
1708 #endif
1709      PARSE_SET(RC_SEEK_FRAG_AREA_IN_CUR, LYSeekFragAREAinCur),
1710      PARSE_SET(RC_SEEK_FRAG_MAP_IN_CUR, LYSeekFragMAPinCur),
1711 #ifdef USE_SESSIONS
1712      PARSE_SET(RC_AUTO_SESSION,         LYAutoSession),
1713      PARSE_STR(RC_SESSION_FILE,         LYSessionFile),
1714      PARSE_FUN(RC_SESSION_LIMIT,        session_limit_fun),
1715 #endif
1716      PARSE_SET(RC_SET_COOKIES,          LYSetCookies),
1717      PARSE_SET(RC_SHORT_URL,            long_url_ok),
1718      PARSE_SET(RC_SHOW_CURSOR,          LYShowCursor),
1719      PARSE_STR(RC_SHOW_KB_NAME,         LYTransferName),
1720      PARSE_ENU(RC_SHOW_KB_RATE,         LYTransferRate, tbl_transfer_rate),
1721      PARSE_Env(RC_SNEWS_PROXY,          0),
1722      PARSE_Env(RC_SNEWSPOST_PROXY,      0),
1723      PARSE_Env(RC_SNEWSREPLY_PROXY,     0),
1724      PARSE_SET(RC_SOFT_DQUOTES,         soft_dquotes),
1725 #ifdef USE_SOURCE_CACHE
1726      PARSE_ENU(RC_SOURCE_CACHE,         LYCacheSource, tbl_source_cache),
1727      PARSE_ENU(RC_SOURCE_CACHE_FOR_ABORTED, LYCacheSourceForAborted, tbl_abort_source_cache),
1728 #endif
1729      PARSE_STR(RC_SSL_CERT_FILE,        SSL_cert_file),
1730      PARSE_STR(RC_SSL_CLIENT_CERT_FILE, SSL_client_cert_file),
1731      PARSE_STR(RC_SSL_CLIENT_KEY_FILE,  SSL_client_key_file),
1732      PARSE_FUN(RC_STARTFILE,            startfile_fun),
1733      PARSE_FUN(RC_STATUS_BUFFER_SIZE,   status_buffer_size_fun),
1734      PARSE_SET(RC_STRIP_DOTDOT_URLS,    LYStripDotDotURLs),
1735      PARSE_SET(RC_SUBSTITUTE_UNDERSCORES, use_underscore),
1736      PARSE_FUN(RC_SUFFIX,               suffix_fun),
1737      PARSE_FUN(RC_SUFFIX_ORDER,         suffix_order_fun),
1738 #ifdef SYSLOG_REQUESTED_URLS
1739      PARSE_SET(RC_SYSLOG_REQUESTED_URLS, syslog_requested_urls),
1740      PARSE_STR(RC_SYSLOG_TEXT,          syslog_txt),
1741 #endif
1742      PARSE_FUN(RC_SYSTEM_EDITOR,        system_editor_fun),
1743      PARSE_STR(RC_SYSTEM_MAIL,          system_mail),
1744      PARSE_STR(RC_SYSTEM_MAIL_FLAGS,    system_mail_flags),
1745      PARSE_FUN(RC_TAGSOUP,              get_tagsoup),
1746      PARSE_PRG(RC_TAR_PATH,             ppTAR),
1747      PARSE_PRG(RC_TELNET_PATH,          ppTELNET),
1748 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
1749      PARSE_SET(RC_TEXTFIELDS_NEED_ACTIVATION, textfields_activation_option),
1750 #endif
1751      PARSE_PRG(RC_TN3270_PATH,          ppTN3270),
1752 #if defined(_WINDOWS)
1753      PARSE_INT(RC_TIMEOUT,              lynx_timeout),
1754 #endif
1755      PARSE_PRG(RC_TOUCH_PATH,           ppTOUCH),
1756      PARSE_SET(RC_TRACK_INTERNAL_LINKS, track_internal_links),
1757      PARSE_SET(RC_TRIM_BLANK_LINES,     LYtrimBlankLines),
1758      PARSE_SET(RC_TRIM_INPUT_FIELDS,    LYtrimInputFields),
1759 #ifdef EXEC_LINKS
1760      PARSE_DEF(RC_TRUSTED_EXEC,         EXEC_PATH),
1761 #endif
1762 #ifdef LYNXCGI_LINKS
1763      PARSE_DEF(RC_TRUSTED_LYNXCGI,      CGI_PATH),
1764 #endif
1765      PARSE_PRG(RC_UNCOMPRESS_PATH,      ppUNCOMPRESS),
1766      PARSE_SET(RC_UNDERLINE_LINKS,      LYUnderlineLinks),
1767      PARSE_SET(RC_UNIQUE_URLS,          unique_urls),
1768      PARSE_PRG(RC_UNZIP_PATH,           ppUNZIP),
1769 #ifdef DIRED_SUPPORT
1770      PARSE_ADD(RC_UPLOADER,             uploaders),
1771 #endif
1772      PARSE_STR(RC_URL_DOMAIN_PREFIXES,  URLDomainPrefixes),
1773      PARSE_STR(RC_URL_DOMAIN_SUFFIXES,  URLDomainSuffixes),
1774 #ifdef VMS
1775      PARSE_SET(RC_USE_FIXED_RECORDS,    UseFixedRecords),
1776 #endif
1777 #if defined(USE_MOUSE)
1778      PARSE_SET(RC_USE_MOUSE,            LYUseMouse),
1779 #endif
1780      PARSE_SET(RC_USE_SELECT_POPUPS,    LYSelectPopups),
1781      PARSE_PRG(RC_UUDECODE_PATH,        ppUUDECODE),
1782      PARSE_SET(RC_VERBOSE_IMAGES,       verbose_img),
1783      PARSE_SET(RC_VI_KEYS_ALWAYS_ON,    vi_keys),
1784      PARSE_FUN(RC_VIEWER,               viewer_fun),
1785      PARSE_Env(RC_WAIS_PROXY,           0),
1786      PARSE_SET(RC_WAIT_VIEWER_TERMINATION, wait_viewer_termination),
1787      PARSE_SET(RC_WITH_BACKSPACES,      with_backspaces),
1788      PARSE_STR(RC_XLOADIMAGE_COMMAND,   XLoadImageCommand),
1789      PARSE_SET(RC_XHTML_PARSING,        LYxhtml_parsing),
1790      PARSE_PRG(RC_ZCAT_PATH,            ppZCAT),
1791      PARSE_PRG(RC_ZIP_PATH,             ppZIP),
1792 
1793      PARSE_NIL
1794 };
1795 /* *INDENT-ON* */
1796 
1797 static char *lynxcfginfo_url = NULL;	/* static */
1798 
1799 #if defined(HAVE_CONFIG_H) && !defined(NO_CONFIG_INFO)
1800 static char *configinfo_url = NULL;	/* static */
1801 #endif
1802 
1803 /*
1804  * Free memory allocated in 'read_cfg()'
1805  */
free_lynx_cfg(void)1806 void free_lynx_cfg(void)
1807 {
1808     Config_Type *tbl;
1809 
1810     for (tbl = Config_Table; tbl->name != 0; tbl++) {
1811 	ParseUnionPtr q = ParseUnionOf(tbl);
1812 
1813 	switch (tbl->type) {
1814 	case CONF_ENV:
1815 	    if (q->str_value != 0) {
1816 		char *name = *(q->str_value);
1817 		char *eqls = StrChr(name, '=');
1818 
1819 		if (eqls != 0) {
1820 		    *eqls = 0;
1821 #ifdef VMS
1822 		    Define_VMSLogical(name, NULL);
1823 #else
1824 # ifdef HAVE_PUTENV
1825 		    if (putenv(name))
1826 			break;
1827 # else
1828 		    unsetenv(name);
1829 # endif
1830 #endif
1831 		}
1832 		FREE(*(q->str_value));
1833 		FREE(q->str_value);
1834 		/* is it enough for reload_read_cfg() to clean up
1835 		 * the result of putenv()?  No for certain platforms.
1836 		 */
1837 	    }
1838 	    break;
1839 	default:
1840 	    break;
1841 	}
1842     }
1843     free_all_item_lists();
1844 #ifdef DIRED_SUPPORT
1845     reset_dired_menu();		/* frees and resets dired menu items - kw */
1846 #endif
1847     FREE(lynxcfginfo_url);
1848 #if defined(HAVE_CONFIG_H) && !defined(NO_CONFIG_INFO)
1849     FREE(configinfo_url);
1850 #endif
1851 }
1852 
lookup_config(const char * name)1853 static Config_Type *lookup_config(const char *name)
1854 {
1855     Config_Type *tbl = Config_Table;
1856     char ch = (char) TOUPPER(*name);
1857 
1858     while (tbl->name != 0) {
1859 	char ch1 = tbl->name[0];
1860 
1861 	if ((ch == TOUPPER(ch1))
1862 	    && (0 == strcasecomp(name, tbl->name)))
1863 	    break;
1864 
1865 	tbl++;
1866     }
1867     return tbl;
1868 }
1869 
1870 /*
1871  * If the given value is an absolute path (by syntax), or we can read it, use
1872  * the value as given.  Otherwise, assume it must be in the same place we read
1873  * the parent configuration file from.
1874  *
1875  * Note:  only read files from the current directory if there's no parent
1876  * filename, otherwise it leads to user surprise.
1877  */
actual_filename(const char * cfg_filename,const char * parent_filename,const char * dft_filename)1878 static char *actual_filename(const char *cfg_filename,
1879 			     const char *parent_filename,
1880 			     const char *dft_filename)
1881 {
1882     char *my_filename = NULL;
1883 
1884     if (!LYisAbsPath(cfg_filename)
1885 	&& !(parent_filename == 0 && LYCanReadFile(cfg_filename))) {
1886 	if (LYIsTilde(cfg_filename[0]) && LYIsPathSep(cfg_filename[1])) {
1887 	    HTSprintf0(&my_filename, "%s%s", Home_Dir(), cfg_filename + 1);
1888 	} else {
1889 	    if (parent_filename != 0) {
1890 		StrAllocCopy(my_filename, parent_filename);
1891 		*LYPathLeaf(my_filename) = '\0';
1892 		StrAllocCat(my_filename, cfg_filename);
1893 	    }
1894 	    if (my_filename == 0 || !LYCanReadFile(my_filename)) {
1895 		StrAllocCopy(my_filename, dft_filename);
1896 		*LYPathLeaf(my_filename) = '\0';
1897 		StrAllocCat(my_filename, cfg_filename);
1898 		if (!LYCanReadFile(my_filename)) {
1899 		    StrAllocCopy(my_filename,
1900 				 LYFindConfigFile(cfg_filename,
1901 						  dft_filename));
1902 		}
1903 	    }
1904 	}
1905     } else {
1906 	StrAllocCopy(my_filename, cfg_filename);
1907     }
1908     return my_filename;
1909 }
1910 
LYOpenCFG(const char * cfg_filename,const char * parent_filename,const char * dft_filename)1911 FILE *LYOpenCFG(const char *cfg_filename,
1912 		const char *parent_filename,
1913 		const char *dft_filename)
1914 {
1915     char *my_file = actual_filename(cfg_filename, parent_filename, dft_filename);
1916     FILE *result;
1917 
1918     CTRACE((tfp, "opening config file %s\n", my_file));
1919     result = fopen(my_file, TXT_R);
1920     FREE(my_file);
1921 
1922     return result;
1923 }
1924 
1925 #define NOPTS_ ( TABLESIZE(Config_Table) - 1 )
1926 typedef BOOL (optidx_set_t)[NOPTS_];
1927 
1928  /* if element is FALSE, then it's allowed in the current file */
1929 
1930 #define optidx_set_AND(r,a,b) \
1931     {\
1932 	unsigned i1;\
1933 	for (i1 = 0; i1 < NOPTS_; ++i1) \
1934 	    (r)[i1]= (BOOLEAN) ((a)[i1] || (b)[i1]); \
1935     }
1936 
1937 /*
1938  * For simple (boolean, string, integer, time) values, set the corresponding
1939  * configuration variable.
1940  */
LYSetConfigValue(const char * name,const char * param)1941 BOOL LYSetConfigValue(const char *name,
1942 		      const char *param)
1943 {
1944     BOOL changed = TRUE;
1945     char *value = NULL;
1946     Config_Type *tbl = lookup_config(name);
1947     ParseUnionPtr q = ParseUnionOf(tbl);
1948     char *temp_name = 0;
1949     char *temp_value = 0;
1950 
1951     if (param == NULL)
1952 	param = "";
1953     StrAllocCopy(value, param);
1954     switch (tbl->type) {
1955     case CONF_BOOL:
1956 	if (q->set_value != 0)
1957 	    *(q->set_value) = is_true(value);
1958 	break;
1959 
1960     case CONF_FUN:
1961 	if (q->fun_value != 0)
1962 	    (*(q->fun_value)) (value);
1963 	break;
1964 
1965     case CONF_TIME:
1966 	if (q->int_value != 0) {
1967 	    float ival;
1968 
1969 	    if (1 == LYscanFloat(value, &ival)) {
1970 		*(q->int_value) = (int) SECS2Secs(ival);
1971 	    }
1972 	}
1973 	break;
1974 
1975     case CONF_ENUM:
1976 	if (tbl->table != 0)
1977 	    LYgetEnum(tbl->table, value, q->int_value);
1978 	break;
1979 
1980     case CONF_INT:
1981 	if (q->int_value != 0) {
1982 	    int ival;
1983 
1984 	    if (1 == sscanf(value, "%d", &ival))
1985 		*(q->int_value) = ival;
1986 	}
1987 	break;
1988 
1989     case CONF_STR:
1990 	if (q->str_value != 0)
1991 	    StrAllocCopy(*(q->str_value), value);
1992 	break;
1993 
1994     case CONF_ENV:
1995     case CONF_ENV2:
1996 
1997 	if (StrAllocCopy(temp_name, name)) {
1998 	    if (tbl->type == CONF_ENV)
1999 		LYLowerCase(temp_name);
2000 	    else
2001 		LYUpperCase(temp_name);
2002 
2003 	    if (LYGetEnv(temp_name) == 0) {
2004 #ifdef VMS
2005 		Define_VMSLogical(temp_name, value);
2006 #else
2007 		if (q->str_value == 0) {
2008 		    q->str_value = typecalloc(char *);
2009 
2010 		    if (q->str_value == 0)
2011 			outofmem(__FILE__, "LYSetConfigValue");
2012 		}
2013 
2014 		HTSprintf0(q->str_value, "%s=%s", temp_name, value);
2015 		putenv(*(q->str_value));
2016 #endif
2017 	    }
2018 	    FREE(temp_name);
2019 	}
2020 	break;
2021     case CONF_ADD_ITEM:
2022 	if (q->add_value != 0)
2023 	    add_item_to_list(value,
2024 			     q->add_value,
2025 			     (q->add_value == &printers),
2026 			     FALSE);
2027 	break;
2028 
2029     case CONF_ADD_STRING:
2030 	if (*(q->lst_value) == NULL) {
2031 	    *(q->lst_value) = HTList_new();
2032 	}
2033 	temp_value = NULL;
2034 	StrAllocCopy(temp_value, value);
2035 	HTList_appendObject(*(q->lst_value), temp_value);
2036 	temp_value = NULL;
2037 	break;
2038 
2039 #if defined(EXEC_LINKS) || defined(LYNXCGI_LINKS)
2040     case CONF_ADD_TRUSTED:
2041 	add_trusted(value, (int) q->def_value);
2042 	break;
2043 #endif
2044 
2045     case CONF_PRG:
2046 	if (isEmpty(value)) {
2047 	    HTSetProgramPath((ProgramPaths) (q->def_value), NULL);
2048 	} else if (StrAllocCopy(temp_value, value)) {
2049 	    HTSetProgramPath((ProgramPaths) (q->def_value), temp_value);
2050 	}
2051 	break;
2052 
2053     default:
2054 	changed = FALSE;
2055 	break;
2056     }
2057     FREE(value);
2058 
2059     return changed;
2060 }
2061 
2062 /*
2063  * Process the configuration file (lynx.cfg).
2064  *
2065  * 'allowed' is a pointer to HTList of allowed options.  Since the included
2066  * file can also include other files with a list of acceptable options, these
2067  * lists are ANDed.
2068  */
do_read_cfg(const char * cfg_filename,const char * parent_filename,int nesting_level,FILE * fp0,optidx_set_t * allowed)2069 static void do_read_cfg(const char *cfg_filename,
2070 			const char *parent_filename,
2071 			int nesting_level,
2072 			FILE *fp0,
2073 			optidx_set_t *allowed)
2074 {
2075     FILE *fp;
2076     char *buffer = 0;
2077 
2078     CTRACE((tfp, "Loading cfg file '%s'.\n", cfg_filename));
2079 
2080     /*
2081      * Don't get hung up by an include file loop.  Arbitrary max depth
2082      * of 10.  - BL
2083      */
2084     if (nesting_level > 10) {
2085 	fprintf(stderr,
2086 		gettext("More than %d nested lynx.cfg includes -- perhaps there is a loop?!?\n"),
2087 		nesting_level - 1);
2088 	fprintf(stderr, gettext("Last attempted include was '%s',\n"), cfg_filename);
2089 	fprintf(stderr, gettext("included from '%s'.\n"), parent_filename);
2090 	exit_immediately(EXIT_FAILURE);
2091     }
2092     /*
2093      * Locate and open the file.
2094      */
2095     if (!cfg_filename || strlen(cfg_filename) == 0) {
2096 	CTRACE((tfp, "No filename following -cfg switch!\n"));
2097 	return;
2098     }
2099     if ((fp = LYOpenCFG(cfg_filename, parent_filename, LYNX_CFG_FILE)) == 0) {
2100 	CTRACE((tfp, "lynx.cfg file not found as '%s'\n", cfg_filename));
2101 	return;
2102     }
2103     have_read_cfg = TRUE;
2104 
2105     /*
2106      * Process each line in the file.
2107      */
2108     if (show_cfg) {
2109 	time_t t;
2110 
2111 	time(&t);
2112 	printf("### %s %s, at %s", LYNX_NAME, LYNX_VERSION, ctime(&t));
2113     }
2114     while (LYSafeGets(&buffer, fp) != 0) {
2115 	char *name, *value;
2116 	char *cp;
2117 	Config_Type *tbl;
2118 
2119 	/* Most lines in the config file are comment lines.  Weed them out
2120 	 * now.  Also, leading whitespace is ok, so trim it.
2121 	 */
2122 	name = LYSkipBlanks(buffer);
2123 
2124 	if (ispunct(UCH(*name)))
2125 	    continue;
2126 
2127 	LYTrimTrailing(name);
2128 
2129 	if (*name == 0)
2130 	    continue;
2131 
2132 	/* Significant lines are of the form KEYWORD:WHATEVER */
2133 	if ((value = StrChr(name, ':')) == 0) {
2134 	    /* fprintf (stderr, "Bad line-- no :\n"); */
2135 	    CTRACE((tfp, "LYReadCFG: missing ':' %s\n", name));
2136 	    continue;
2137 	}
2138 
2139 	/* skip past colon, but replace ':' with 0 to make name meaningful */
2140 	*value++ = 0;
2141 
2142 	/*
2143 	 * Trim off any trailing comments.
2144 	 *
2145 	 * (Apparently, the original code considers a trailing comment valid
2146 	 * only if preceded by a space character but is not followed by a
2147 	 * colon.  -- JED)
2148 	 */
2149 	if ((cp = strrchr(value, ':')) == 0)
2150 	    cp = value;
2151 	if ((cp = StrChr(cp, '#')) != 0) {
2152 	    cp--;
2153 	    if (isspace(UCH(*cp)))
2154 		*cp = 0;
2155 	}
2156 
2157 	CTRACE2(TRACE_CFG, (tfp, "LYReadCFG %s:%s\n", name, value));
2158 	tbl = lookup_config(name);
2159 	if (tbl->name == 0) {
2160 	    /* lynx ignores unknown keywords */
2161 	    CTRACE((tfp, "LYReadCFG: ignored %s:%s\n", name, value));
2162 	    continue;
2163 	}
2164 	if (show_cfg)
2165 	    printf("%s:%s\n", name, value);
2166 
2167 	if (allowed && (*allowed)[tbl - Config_Table]) {
2168 	    if (fp0 == NULL)
2169 		fprintf(stderr, "%s is not allowed in the %s\n",
2170 			name, cfg_filename);
2171 	    /*FIXME: we can do something wiser if we are generating
2172 	       the html representation of lynx.cfg - say include this line
2173 	       in bold, or something... */
2174 
2175 	    continue;
2176 	}
2177 
2178 	(void) ParseUnionOf(tbl);
2179 	switch ((fp0 != 0 && tbl->type != CONF_INCLUDE)
2180 		? CONF_NIL
2181 		: tbl->type) {
2182 	case CONF_BOOL:
2183 	case CONF_FUN:
2184 	case CONF_TIME:
2185 	case CONF_ENUM:
2186 	case CONF_INT:
2187 	case CONF_STR:
2188 	case CONF_ENV:
2189 	case CONF_ENV2:
2190 	case CONF_PRG:
2191 	case CONF_ADD_ITEM:
2192 	case CONF_ADD_STRING:
2193 	case CONF_ADD_TRUSTED:
2194 	    LYSetConfigValue(name, value);
2195 	    break;
2196 
2197 	case CONF_INCLUDE:{
2198 		/* include another file */
2199 		optidx_set_t cur_set, anded_set;
2200 		optidx_set_t *resultant_set = NULL;
2201 		char *p1, *p2, savechar;
2202 		BOOL any_optname_found = FALSE;
2203 
2204 		char *url = NULL;
2205 		char *cp1 = NULL;
2206 		const char *sep = NULL;
2207 
2208 		if ((p1 = strstr(value, sep = " for ")) != 0
2209 #if defined(UNIX) && !defined(USE_DOS_DRIVES)
2210 		    || (p1 = strstr(value, sep = ":")) != 0
2211 #endif
2212 		    ) {
2213 		    *p1 = '\0';
2214 		    p1 += strlen(sep);
2215 		}
2216 #ifndef NO_CONFIG_INFO
2217 		if (fp0 != 0 && !no_lynxcfg_xinfo) {
2218 		    char *my_file = actual_filename(value, cfg_filename, LYNX_CFG_FILE);
2219 
2220 		    LYLocalFileToURL(&url, my_file);
2221 		    FREE(my_file);
2222 		    StrAllocCopy(cp1, value);
2223 		    if (StrChr(value, '&') || StrChr(value, '<')) {
2224 			LYEntify(&cp1, TRUE);
2225 		    }
2226 
2227 		    fprintf(fp0, "%s:<a href=\"%s\">%s</a>\n\n", name, url, cp1);
2228 		    fprintf(fp0, "    #&lt;begin  %s&gt;\n", cp1);
2229 		}
2230 #endif
2231 
2232 		if (p1) {
2233 		    while (*(p1 = LYSkipBlanks(p1)) != 0) {
2234 			Config_Type *tbl2;
2235 
2236 			p2 = LYSkipNonBlanks(p1);
2237 			savechar = *p2;
2238 			*p2 = 0;
2239 
2240 			tbl2 = lookup_config(p1);
2241 			if (tbl2->name == 0) {
2242 			    if (fp0 == NULL)
2243 				fprintf(stderr,
2244 					"unknown option name %s in %s\n",
2245 					p1, cfg_filename);
2246 			} else {
2247 			    unsigned i;
2248 
2249 			    if (!any_optname_found) {
2250 				any_optname_found = TRUE;
2251 				for (i = 0; i < NOPTS_; ++i)
2252 				    cur_set[i] = TRUE;
2253 			    }
2254 			    cur_set[tbl2 - Config_Table] = FALSE;
2255 			}
2256 			if (savechar && p2[1])
2257 			    p1 = p2 + 1;
2258 			else
2259 			    break;
2260 		    }
2261 		}
2262 		if (!allowed) {
2263 		    if (!any_optname_found)
2264 			resultant_set = NULL;
2265 		    else
2266 			resultant_set = &cur_set;
2267 		} else {
2268 		    if (!any_optname_found)
2269 			resultant_set = allowed;
2270 		    else {
2271 			optidx_set_AND(anded_set, *allowed, cur_set);
2272 			resultant_set = &anded_set;
2273 		    }
2274 		}
2275 
2276 #ifndef NO_CONFIG_INFO
2277 		/*
2278 		 * Now list the opts that are allowed in included file.  If all
2279 		 * opts are allowed, then emit nothing, else emit an effective set
2280 		 * of allowed options in <ul>.  Option names will be uppercased.
2281 		 * FIXME:  uppercasing option names can be considered redundant.
2282 		 */
2283 		if (fp0 != 0 && !no_lynxcfg_xinfo && resultant_set) {
2284 		    char *buf = NULL;
2285 		    unsigned i;
2286 
2287 		    fprintf(fp0, "     Options allowed in this file:\n");
2288 		    for (i = 0; i < NOPTS_; ++i) {
2289 			if ((*resultant_set)[i])
2290 			    continue;
2291 			StrAllocCopy(buf, Config_Table[i].name);
2292 			LYUpperCase(buf);
2293 			fprintf(fp0, "         * %s\n", buf);
2294 		    }
2295 		    FREE(buf);
2296 		}
2297 #endif
2298 		do_read_cfg(value, cfg_filename, nesting_level + 1, fp0, resultant_set);
2299 
2300 #ifndef NO_CONFIG_INFO
2301 		if (fp0 != 0 && !no_lynxcfg_xinfo) {
2302 		    fprintf(fp0, "    #&lt;end of %s&gt;\n\n", cp1);
2303 		    FREE(url);
2304 		    FREE(cp1);
2305 		}
2306 #endif
2307 	    }
2308 	    break;
2309 
2310 	default:
2311 	    if (fp0 != 0) {
2312 		if (StrChr(value, '&') || StrChr(value, '<')) {
2313 		    char *cp1 = NULL;
2314 
2315 		    StrAllocCopy(cp1, value);
2316 		    LYEntify(&cp1, TRUE);
2317 		    fprintf(fp0, "%s:%s\n", name, cp1);
2318 		    FREE(cp1);
2319 		} else {
2320 		    fprintf(fp0, "%s:%s\n", name, value);
2321 		}
2322 	    }
2323 	    break;
2324 	}
2325     }
2326 
2327     LYCloseInput(fp);
2328 
2329     /*
2330      * If any DOWNLOADER:  commands have always_enabled set (:TRUE), make
2331      * override_no_download TRUE, so that other restriction settings will not
2332      * block presentation of a download menu with those always_enabled options
2333      * still available.  - FM
2334      */
2335     if (downloaders != 0) {
2336 	lynx_list_item_type *cur_download;
2337 
2338 	cur_download = downloaders;
2339 	while (cur_download != 0) {
2340 	    if (cur_download->always_enabled) {
2341 		override_no_download = TRUE;
2342 		break;
2343 	    }
2344 	    cur_download = cur_download->next;
2345 	}
2346     }
2347 
2348     /*
2349      * If any COOKIE_{ACCEPT,REJECT}_DOMAINS have been defined,
2350      * process them.  These are comma delimited lists of
2351      * domains. - BJP
2352      *
2353      * And for query/strict/loose invalid cookie checking. - BJP
2354      */
2355     LYConfigCookies();
2356 
2357     /*
2358      * Do not allow infinite redirection loops.
2359      */
2360     if (redirection_limit < 5)
2361 	redirection_limit = 5;
2362     if (redirection_limit > 25)
2363 	redirection_limit = 25;
2364 }
2365 
2366 /* this is a public interface to do_read_cfg */
read_cfg(const char * cfg_filename,const char * parent_filename,int nesting_level,FILE * fp0)2367 void read_cfg(const char *cfg_filename,
2368 	      const char *parent_filename,
2369 	      int nesting_level,
2370 	      FILE *fp0)
2371 {
2372     HTInitProgramPaths(TRUE);
2373     do_read_cfg(cfg_filename, parent_filename, nesting_level, fp0, NULL);
2374 }
2375 
2376 #ifndef NO_CONFIG_INFO
extra_cfg_link(FILE * fp,const char * href,const char * name)2377 static void extra_cfg_link(FILE *fp, const char *href,
2378 			   const char *name)
2379 {
2380     fprintf(fp, "<a href=\"%s\">%s</a>",
2381 	    href, name);
2382 }
2383 #endif /* NO_CONFIG_INFO */
2384 
2385 /*
2386  * Show rendered lynx.cfg data without comments, LYNXCFG:/ internal page.
2387  * Called from getfile() cycle:  we create and load the page just in place and
2388  * return to mainloop().
2389  */
lynx_cfg_infopage(DocInfo * newdoc)2390 int lynx_cfg_infopage(DocInfo *newdoc)
2391 {
2392     static char tempfile[LY_MAXPATH] = "\0";
2393     DocAddress WWWDoc;		/* need on exit */
2394     char *temp = 0;
2395     char *cp1 = NULL;
2396     FILE *fp0;
2397 
2398 #ifndef NO_CONFIG_INFO
2399     /*-------------------------------------------------
2400      * kludge a link from LYNXCFG:/, the URL was:
2401      * "  <a href=\"LYNXCFG://reload\">RELOAD THE CHANGES</a>\n"
2402      *--------------------------------------------------*/
2403 
2404     if (!no_lynxcfg_xinfo && (strstr(newdoc->address, "LYNXCFG://reload"))) {
2405 	/*
2406 	 * Some stuff to reload read_cfg(), but also load options menu items
2407 	 * and command-line options to make things consistent.  Implemented in
2408 	 * LYMain.c
2409 	 */
2410 	reload_read_cfg();
2411 
2412 	/*
2413 	 * now pop-up and return to updated LYNXCFG:/ page, remind
2414 	 * postoptions() but much simpler:
2415 	 */
2416 	/*
2417 	 * But check whether the top history document is really the expected
2418 	 * LYNXCFG:  page.  - kw
2419 	 */
2420 	if (HTMainText && nhist > 0 &&
2421 	    !strcmp(HTLoadedDocumentTitle(), LYNXCFG_TITLE) &&
2422 	    !strcmp(HTLoadedDocumentURL(), HDOC(nhist - 1).address) &&
2423 	    LYIsUIPage(HDOC(nhist - 1).address, UIP_LYNXCFG) &&
2424 	    (!lynxcfginfo_url ||
2425 	     strcmp(HTLoadedDocumentURL(), lynxcfginfo_url))) {
2426 	    /*  the page was pushed, so pop-up. */
2427 	    LYpop(newdoc);
2428 	    WWWDoc.address = newdoc->address;
2429 	    WWWDoc.post_data = newdoc->post_data;
2430 	    WWWDoc.post_content_type = newdoc->post_content_type;
2431 	    WWWDoc.bookmark = newdoc->bookmark;
2432 	    WWWDoc.isHEAD = newdoc->isHEAD;
2433 	    WWWDoc.safe = newdoc->safe;
2434 	    LYforce_no_cache = FALSE;	/* ! */
2435 	    LYoverride_no_cache = TRUE;		/* ! */
2436 
2437 	    /*
2438 	     * Working out of getfile() cycle we reset *no_cache manually here
2439 	     * so HTLoadAbsolute() will return "Document already in memory":
2440 	     * it was forced reloading obsolete file again without this
2441 	     * (overhead).
2442 	     *
2443 	     * Probably *no_cache was set in a wrong position because of the
2444 	     * internal page...
2445 	     */
2446 	    if (!HTLoadAbsolute(&WWWDoc))
2447 		return (NOT_FOUND);
2448 
2449 	    HTuncache_current_document();	/* will never use again */
2450 	    LYUnRegisterUIPage(UIP_LYNXCFG);
2451 	}
2452 
2453 	/*  now set up the flag and fall down to create a new LYNXCFG:/ page */
2454 	FREE(lynxcfginfo_url);	/* see below */
2455     }
2456 #endif /* !NO_CONFIG_INFO */
2457 
2458     /*
2459      * We regenerate the file if reloading has been requested (with LYK_NOCACHE
2460      * key).  If we did not regenerate, there would be no way to recover in a
2461      * session from a situation where the file is corrupted (for example
2462      * truncated because the file system was full when it was first created -
2463      * lynx doesn't check for write errors below), short of manual complete
2464      * removal or perhaps forcing regeneration with LYNXCFG://reload.
2465      * Similarly, there would be no simple way to get a different page if
2466      * user_mode has changed to Advanced after the file was first generated in
2467      * a non-Advanced mode (the difference being in whether the page includes
2468      * the link to LYNXCFG://reload or not).
2469      *
2470      * We also try to regenerate the file if lynxcfginfo_url is set, indicating
2471      * that tempfile is valid, but the file has disappeared anyway.  This can
2472      * happen to a long-lived lynx process if for example some system script
2473      * periodically cleans up old files in the temp file space.  - kw
2474      */
2475 
2476     if (LYforce_no_cache && reloading) {
2477 	FREE(lynxcfginfo_url);	/* flag to code below to regenerate - kw */
2478     } else if (lynxcfginfo_url != NULL) {
2479 	if (!LYCanReadFile(tempfile)) {		/* check existence */
2480 	    FREE(lynxcfginfo_url);	/* flag to code below to try again - kw */
2481 	}
2482     }
2483     if (lynxcfginfo_url == 0) {
2484 
2485 	if ((fp0 = InternalPageFP(tempfile, TRUE)) == 0)
2486 	    return (NOT_FOUND);
2487 
2488 	LYLocalFileToURL(&lynxcfginfo_url, tempfile);
2489 
2490 	LYforce_no_cache = TRUE;	/* don't cache this doc */
2491 
2492 	BeginInternalPage(fp0, LYNXCFG_TITLE, NULL);
2493 	fprintf(fp0, "<pre>\n");
2494 
2495 #ifndef NO_CONFIG_INFO
2496 	if (!no_lynxcfg_xinfo) {
2497 #if defined(HAVE_CONFIG_H) || defined(VMS)
2498 	    if (strcmp(lynx_cfg_file, LYNX_CFG_FILE)) {
2499 		fprintf(fp0, "<em>%s\n%s",
2500 			gettext("The following is read from your lynx.cfg file."),
2501 			gettext("Please read the distribution"));
2502 		LYLocalFileToURL(&temp, LYNX_CFG_FILE);
2503 		fprintf(fp0, " <a href=\"%s\">lynx.cfg</a> ",
2504 			temp);
2505 		FREE(temp);
2506 		fprintf(fp0, "%s</em>\n\n",
2507 			gettext("for more comments."));
2508 	    } else
2509 #endif /* HAVE_CONFIG_H */
2510 	    {
2511 		/* no absolute path... for lynx.cfg on DOS/Win32 */
2512 		fprintf(fp0, "<em>%s\n%s",
2513 			gettext("The following is read from your lynx.cfg file."),
2514 			gettext("Please read the distribution"));
2515 		fprintf(fp0, " </em>lynx.cfg<em> ");
2516 		fprintf(fp0, "%s</em>\n",
2517 			gettext("for more comments."));
2518 	    }
2519 
2520 #ifndef NO_CONFIG_INFO
2521 #if defined(HAVE_CONFIG_H) && defined(USE_COLOR_STYLE)
2522 	    if (!no_compileopts_info && !no_lynxcfg_xinfo) {
2523 		fprintf(fp0, "%s</pre><ul><li>", SEE_ALSO);
2524 		extra_cfg_link(fp0, STR_LYNXCFLAGS, COMPILE_OPT_SEGMENT);
2525 
2526 		fprintf(fp0, "<li>");
2527 		LYLocalFileToURL(&temp, lynx_lss_file);
2528 		extra_cfg_link(fp0, temp, COLOR_STYLE_SEGMENT);
2529 		fprintf(fp0, "</ul><pre>\n");
2530 	    } else
2531 #endif
2532 	    {
2533 		fprintf(fp0, "%s ", SEE_ALSO);
2534 #if defined(HAVE_CONFIG_H)
2535 		if (!no_compileopts_info) {
2536 		    extra_cfg_link(fp0, STR_LYNXCFLAGS, COMPILE_OPT_SEGMENT);
2537 		}
2538 #endif
2539 #if defined(USE_COLOR_STYLE)
2540 		if (!no_lynxcfg_xinfo) {
2541 		    LYLocalFileToURL(&temp, lynx_lss_file);
2542 		    extra_cfg_link(fp0, temp, COLOR_STYLE_SEGMENT);
2543 		}
2544 #endif
2545 		fprintf(fp0, "\n\n");
2546 	    }
2547 #endif /* NO_CONFIG_INFO */
2548 
2549 	    /** a new experimental link ... **/
2550 	    if (user_mode == ADVANCED_MODE)
2551 		fprintf(fp0, "  <a href=\"%s//reload\">%s</a>\n",
2552 			STR_LYNXCFG,
2553 			gettext("RELOAD THE CHANGES"));
2554 
2555 	    LYLocalFileToURL(&temp, lynx_cfg_file);
2556 	    StrAllocCopy(cp1, lynx_cfg_file);
2557 	    if (StrChr(lynx_cfg_file, '&') || StrChr(lynx_cfg_file, '<')) {
2558 		LYEntify(&cp1, TRUE);
2559 	    }
2560 	    fprintf(fp0, "\n    #<em>%s <a href=\"%s\">%s</a></em>\n",
2561 		    gettext("Your primary configuration"),
2562 		    temp,
2563 		    cp1);
2564 	    FREE(temp);
2565 	    FREE(cp1);
2566 
2567 	} else
2568 #endif /* !NO_CONFIG_INFO */
2569 
2570 	    fprintf(fp0, "<em>%s</em>\n\n",
2571 		    gettext("The following is read from your lynx.cfg file."));
2572 
2573 	/*
2574 	 * Process the configuration file.
2575 	 */
2576 	read_cfg(lynx_cfg_file, "main program", 1, fp0);
2577 
2578 	fprintf(fp0, "</pre>\n");
2579 	EndInternalPage(fp0);
2580 	LYCloseTempFP(fp0);
2581 	LYRegisterUIPage(lynxcfginfo_url, UIP_LYNXCFG);
2582     }
2583 
2584     /* return to getfile() cycle */
2585     StrAllocCopy(newdoc->address, lynxcfginfo_url);
2586     WWWDoc.address = newdoc->address;
2587     WWWDoc.post_data = newdoc->post_data;
2588     WWWDoc.post_content_type = newdoc->post_content_type;
2589     WWWDoc.bookmark = newdoc->bookmark;
2590     WWWDoc.isHEAD = newdoc->isHEAD;
2591     WWWDoc.safe = newdoc->safe;
2592 
2593     if (!HTLoadAbsolute(&WWWDoc))
2594 	return (NOT_FOUND);
2595 #ifdef DIRED_SUPPORT
2596     lynx_edit_mode = FALSE;
2597 #endif /* DIRED_SUPPORT */
2598     return (NORMAL);
2599 }
2600 
2601 #if defined(HAVE_CONFIG_H) && !defined(NO_CONFIG_INFO)
2602 /*
2603  * Compile-time definitions info, LYNXCOMPILEOPTS:/ internal page, from
2604  * getfile() cycle.
2605  */
lynx_compile_opts(DocInfo * newdoc)2606 int lynx_compile_opts(DocInfo *newdoc)
2607 {
2608     static char tempfile[LY_MAXPATH] = "\0";
2609 
2610 #define PutDefs(table, N) fprintf(fp0, "%-35s %s\n", table[N].name, table[N].value)
2611 #include <cfg_defs.h>
2612     unsigned n;
2613     DocAddress WWWDoc;		/* need on exit */
2614     FILE *fp0;
2615 
2616     /* In general, create the page only once - compile-time data will not
2617      * change...  But we will regenerate the file anyway, in a few situations:
2618      *
2619      * (a) configinfo_url has been FREEd - this can happen if free_lynx_cfg()
2620      * was called as part of a LYNXCFG://reload action.
2621      *
2622      * (b) reloading has been requested (with LYK_NOCACHE key).  If we did not
2623      * regenerate, there would be no way to recover in a session from a
2624      * situation where the file is corrupted (for example truncated because the
2625      * file system was full when it was first created - lynx doesn't check for
2626      * write errors below), short of manual complete removal or forcing
2627      * regeneration with LYNXCFG://reload.
2628      *
2629      * (c) configinfo_url is set, indicating that tempfile is valid, but the
2630      * file has disappeared anyway.  This can happen to a long-lived lynx
2631      * process if for example some system script periodically cleans up old
2632      * files in the temp file space.  - kw
2633      */
2634 
2635     if (LYforce_no_cache && reloading) {
2636 	FREE(configinfo_url);	/* flag to code below to regenerate - kw */
2637     } else if (configinfo_url != NULL) {
2638 	if (!LYCanReadFile(tempfile)) {		/* check existence */
2639 	    FREE(configinfo_url);	/* flag to code below to try again - kw */
2640 	}
2641     }
2642     if (configinfo_url == NULL) {
2643 	if ((fp0 = InternalPageFP(tempfile, TRUE)) == 0)
2644 	    return (NOT_FOUND);
2645 
2646 	LYLocalFileToURL(&configinfo_url, tempfile);
2647 
2648 	BeginInternalPage(fp0, CONFIG_DEF_TITLE, NULL);
2649 	fprintf(fp0, "<pre>\n");
2650 
2651 	fprintf(fp0, "\n%s<br>\n<em>config.cache</em>\n", AUTOCONF_CONFIG_CACHE);
2652 	for (n = 0; n < TABLESIZE(config_cache); n++) {
2653 	    PutDefs(config_cache, n);
2654 	}
2655 	fprintf(fp0, "\n%s<br>\n<em>lynx_cfg.h</em>\n", AUTOCONF_LYNXCFG_H);
2656 	for (n = 0; n < TABLESIZE(config_defines); n++) {
2657 	    PutDefs(config_defines, n);
2658 	}
2659 	fprintf(fp0, "</pre>\n");
2660 	EndInternalPage(fp0);
2661 	LYCloseTempFP(fp0);
2662 	LYRegisterUIPage(configinfo_url, UIP_CONFIG_DEF);
2663     }
2664 
2665     /* exit to getfile() cycle */
2666     StrAllocCopy(newdoc->address, configinfo_url);
2667     WWWDoc.address = newdoc->address;
2668     WWWDoc.post_data = newdoc->post_data;
2669     WWWDoc.post_content_type = newdoc->post_content_type;
2670     WWWDoc.bookmark = newdoc->bookmark;
2671     WWWDoc.isHEAD = newdoc->isHEAD;
2672     WWWDoc.safe = newdoc->safe;
2673 
2674     if (!HTLoadAbsolute(&WWWDoc))
2675 	return (NOT_FOUND);
2676 #ifdef DIRED_SUPPORT
2677     lynx_edit_mode = FALSE;
2678 #endif /* DIRED_SUPPORT */
2679     return (NORMAL);
2680 }
2681 #endif /* !NO_CONFIG_INFO */
2682