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