1 /* $LynxId: LYOptions.c,v 1.183 2021/07/05 21:17:42 tom Exp $ */
2 #include <HTUtils.h>
3 #include <HTFTP.h>
4 #include <HTTP.h>		/* 'reloading' flag */
5 #include <HTML.h>
6 #include <LYCurses.h>
7 #include <LYUtils.h>
8 #include <LYStrings.h>
9 #include <LYGlobalDefs.h>
10 #include <LYHistory.h>
11 #include <LYOptions.h>
12 #include <LYSignal.h>
13 #include <LYClean.h>
14 #include <LYCharSets.h>
15 #include <UCMap.h>
16 #include <UCAux.h>
17 #include <LYKeymap.h>
18 #include <LYrcFile.h>
19 #include <HTAlert.h>
20 #include <LYBookmark.h>
21 #include <GridText.h>
22 #include <LYGetFile.h>
23 #include <LYReadCFG.h>
24 #include <LYPrettySrc.h>
25 #include <HTFile.h>
26 #include <LYCharUtils.h>
27 
28 #ifdef USE_COLOR_STYLE
29 #include <LYStyle.h>
30 #endif
31 
32 #include <LYLeaks.h>
33 
34 BOOLEAN term_options;
35 
36 #define TOP_LINK  "/"
37 #define MBM_LINK  "//MBM_MENU"
38 
39 #define MARGIN_STR (no_margins ? "" : "&nbsp;&nbsp;")
40 #define MARGIN_LEN (no_margins ?  0 : 2)
41 
42 static void terminate_options(int sig);
43 
44 #define COL_OPTION_VALUES 36	/* display column where option values start */
45 
46 #if defined(USE_SLANG) || defined(COLOR_CURSES)
47 static BOOLEAN can_do_colors = FALSE;
48 #endif
49 
50 static int LYChosenShowColor = SHOW_COLOR_UNKNOWN;	/* whether to show and save */
51 
LYCheckUserAgent(void)52 BOOLEAN LYCheckUserAgent(void)
53 {
54     if (non_empty(LYUserAgent)) {
55 	if (strstr(LYUserAgent, "Lynx") == 0
56 	    && strstr(LYUserAgent, "lynx") == 0
57 	    && strstr(LYUserAgent, "L_y_n_x") == 0
58 	    && strstr(LYUserAgent, "l_y_n_x") == 0) {
59 	    return FALSE;
60 	}
61     }
62     return TRUE;
63 }
64 
validate_x_display(void)65 static void validate_x_display(void)
66 {
67     char *cp;
68 
69     if ((cp = LYgetXDisplay()) != NULL) {
70 	StrAllocCopy(x_display, cp);
71     } else {
72 	FREE(x_display);
73     }
74 }
75 
summarize_x_display(char * display_option)76 static void summarize_x_display(char *display_option)
77 {
78     if ((x_display == NULL && *display_option == '\0') ||
79 	(x_display != NULL && !strcmp(x_display, display_option))) {
80 	if (x_display == NULL && LYisConfiguredForX == TRUE) {
81 	    _statusline(VALUE_ACCEPTED_WARNING_X);
82 	} else if (x_display != NULL && LYisConfiguredForX == FALSE) {
83 	    _statusline(VALUE_ACCEPTED_WARNING_NONX);
84 	} else {
85 	    _statusline(VALUE_ACCEPTED);
86 	}
87     } else {
88 	if (*display_option) {
89 	    _statusline(FAILED_TO_SET_DISPLAY);
90 	} else {
91 	    _statusline(FAILED_CLEAR_SET_DISPLAY);
92 	}
93     }
94 }
95 
SetupChosenShowColor(void)96 static void SetupChosenShowColor(void)
97 {
98 #if defined(USE_SLANG) || defined(COLOR_CURSES)
99     can_do_colors = TRUE;
100 #if defined(COLOR_CURSES)
101     if (LYCursesON)		/* could crash if called before initialization */
102 	can_do_colors = (has_colors()
103 			 ? TRUE
104 			 : FALSE);
105 #endif
106     if (!no_option_save) {
107 	if (LYChosenShowColor == SHOW_COLOR_UNKNOWN) {
108 	    switch (LYrcShowColor) {
109 	    case SHOW_COLOR_NEVER:
110 		LYChosenShowColor =
111 		    (LYShowColor >= SHOW_COLOR_ON) ?
112 		    SHOW_COLOR_ON : SHOW_COLOR_NEVER;
113 		break;
114 	    case SHOW_COLOR_ALWAYS:
115 		if (!can_do_colors)
116 		    LYChosenShowColor = SHOW_COLOR_ALWAYS;
117 		else
118 		    LYChosenShowColor =
119 			(LYShowColor >= SHOW_COLOR_ON) ?
120 			SHOW_COLOR_ALWAYS : SHOW_COLOR_OFF;
121 		break;
122 	    default:
123 		LYChosenShowColor =
124 		    (LYShowColor >= SHOW_COLOR_ON) ?
125 		    SHOW_COLOR_ON : SHOW_COLOR_OFF;
126 	    }
127 	}
128     }
129 #endif /* USE_SLANG || COLOR_CURSES */
130 }
131 
132 #ifndef NO_OPTION_MENU
133 static int boolean_choice(int status,
134 			  int line,
135 			  int column,
136 			  STRING2PTR choices);
137 
138 #define LYChooseBoolean(status, line, column, choices) \
139 	(BOOLEAN) boolean_choice(status, line, column, (const char *const*)choices)
140 
141 #define LYChooseEnum(status, line, column, choices) \
142 	boolean_choice(status, line, column, (const char *const*)choices)
143 
144 #define MAXCHOICES 10
145 
146 /*
147  * Values for the options menu.  - FM
148  *
149  * L_foo values are the Y coordinates for the menu item.
150  * B_foo values are the X coordinates for the item's prompt string.
151  * C_foo values are the X coordinates for the item's value string.
152  */
153 #define L_EDITOR	 2
154 #define L_DISPLAY	 3
155 
156 #define L_HOME		 4
157 #define C_MULTI		24
158 #define B_BOOK		34
159 #define C_DEFAULT	50
160 
161 #define L_FTPSTYPE	 5
162 #define L_MAIL_ADDRESS	 6
163 #define L_SSEARCH	 7
164 #define L_LANGUAGE	 8
165 #define L_PREF_CHARSET	 9
166 #define L_ASSUME_CHARSET (L_PREF_CHARSET + 1)
167 #define L_CHARSET	10
168 #define L_RAWMODE	11
169 
170 #define L_COLOR		L_RAWMODE
171 #define B_COLOR		44
172 #define C_COLOR		62
173 
174 #define L_BOOL_A	12
175 #define B_VIKEYS	5
176 #define C_VIKEYS	15
177 #define B_EMACSKEYS	22
178 #define C_EMACSKEYS	36
179 #define B_SHOW_DOTFILES	44
180 #define C_SHOW_DOTFILES	62
181 
182 #define L_BOOL_B	13
183 #define B_SELECT_POPUPS	5
184 #define C_SELECT_POPUPS	36
185 #define B_SHOW_CURSOR	44
186 #define C_SHOW_CURSOR	62
187 
188 #define L_KEYPAD	14
189 #define L_LINEED	15
190 #define L_LAYOUT	16
191 
192 #ifdef DIRED_SUPPORT
193 #define L_DIRED		17
194 #define L_USER_MODE	18
195 #define L_USER_AGENT	19
196 #define L_EXEC		20
197 #else
198 #define L_USER_MODE	17
199 #define L_USER_AGENT	18
200 #define L_EXEC		19
201 #endif /* DIRED_SUPPORT */
202 
203 #define L_VERBOSE_IMAGES L_USER_MODE
204 #define B_VERBOSE_IMAGES 50
205 #define C_VERBOSE_IMAGES (B_VERBOSE_IMAGES + 21)
206 
207 /* a kludge to add assume_charset only in ADVANCED mode... */
208 #define L_Bool_A     (use_assume_charset ? L_BOOL_A     + 1 : L_BOOL_A)
209 #define L_Bool_B     (use_assume_charset ? L_BOOL_B     + 1 : L_BOOL_B)
210 #define L_Exec       (use_assume_charset ? L_EXEC       + 1 : L_EXEC)
211 #define L_Rawmode    (use_assume_charset ? L_RAWMODE    + 1 : L_RAWMODE)
212 #define L_Charset    (use_assume_charset ? L_CHARSET    + 1 : L_CHARSET)
213 #define L_Color      (use_assume_charset ? L_COLOR      + 1 : L_COLOR)
214 #define L_Keypad     (use_assume_charset ? L_KEYPAD     + 1 : L_KEYPAD)
215 #define L_Lineed     (use_assume_charset ? L_LINEED     + 1 : L_LINEED)
216 #define L_Layout     (use_assume_charset ? L_LAYOUT     + 1 : L_LAYOUT)
217 #define L_Dired      (use_assume_charset ? L_DIRED      + 1 : L_DIRED)
218 #define L_User_Mode  (use_assume_charset ? L_USER_MODE  + 1 : L_USER_MODE)
219 #define L_User_Agent (use_assume_charset ? L_USER_AGENT + 1 : L_USER_AGENT)
220 
221 #define LPAREN '('
222 #define RPAREN ')'
223 
add_it(char * text,int len)224 static int add_it(char *text, int len)
225 {
226     if (len) {
227 	text[len] = '\0';
228 	LYaddstr(text);
229     }
230     return 0;
231 }
232 
233 /*
234  * addlbl() is used instead of plain LYaddstr() in old-style options menu
235  * to show hot keys in bold.
236  */
addlbl(const char * text)237 static void addlbl(const char *text)
238 {
239     char actual[80];
240     int s, d;
241     BOOL b = FALSE;
242 
243     for (s = d = 0; text[s]; s++) {
244 	actual[d++] = text[s];
245 	if (text[s] == LPAREN) {
246 	    d = add_it(actual, d - 1);
247 	    lynx_start_bold();
248 	    b = TRUE;
249 	    actual[d++] = text[s];
250 	} else if (text[s] == RPAREN) {
251 	    d = add_it(actual, d);
252 	    lynx_stop_bold();
253 	    b = FALSE;
254 	}
255     }
256     add_it(actual, d);
257     if (b)
258 	lynx_stop_bold();
259 }
260 
261 #if !defined(VMS) || defined(USE_SLANG)
262 #define HANDLE_LYOPTIONS \
263 		    if (term_options) { \
264 			term_options = FALSE; \
265 		    } else { \
266 			AddValueAccepted = TRUE; \
267 		    } \
268 		    goto draw_options
269 #else
270 #define HANDLE_LYOPTIONS \
271 		    term_options = FALSE; \
272 		    if (use_assume_charset != old_use_assume_charset) \
273 			goto draw_options
274 #endif /* !VMS || USE_SLANG */
275 
LYoptions(void)276 void LYoptions(void)
277 {
278 #define ShowBool(value) LYaddstr((value) ? "ON " : "OFF")
279     static const char *bool_choices[] =
280     {
281 	"OFF",
282 	"ON",
283 	NULL
284     };
285     static const char *const caseless_choices[] =
286     {
287 	"CASE INSENSITIVE",
288 	"CASE SENSITIVE",
289 	NULL
290     };
291 
292 #ifdef DIRED_SUPPORT
293     static const char *dirList_choices[] =
294     {
295 	"Directories first",
296 	"Files first",
297 	"Mixed style",
298 	NULL
299     };
300 #endif
301 
302 #if defined(ENABLE_OPTS_CHANGE_EXEC) && (defined(EXEC_LINKS) || defined(EXEC_SCRIPTS))
303     static const char *exec_choices[] =
304     {
305 	"ALWAYS OFF",
306 	"FOR LOCAL FILES ONLY",
307 #ifndef NEVER_ALLOW_REMOTE_EXEC
308 	"ALWAYS ON",
309 #endif				/* !NEVER_ALLOW_REMOTE_EXEC */
310 	NULL
311     };
312 #endif
313     static const char *fileSort_choices[] =
314     {
315 	"By Filename",
316 	"By Type",
317 	"By Size",
318 	"By Date",
319 	NULL
320     };
321     static const char *keypad_choices[] =
322     {
323 	"Numbers act as arrows",
324 	"Links are numbered",
325 	"Links and form fields are numbered",
326 	NULL
327     };
328     static const char *mbm_choices[] =
329     {
330 	"OFF     ",
331 	"STANDARD",
332 	"ADVANCED",
333 	NULL
334     };
335     static const char *userMode_choices[] =
336     {
337 	"Novice",
338 	"Intermediate",
339 	"Advanced",
340 	NULL
341     };
342 
343 #if defined(ENABLE_OPTS_CHANGE_EXEC) && (defined(EXEC_LINKS) || defined(EXEC_SCRIPTS))
344     int itmp;
345 #endif /* ENABLE_OPTS_CHANGE_EXEC */
346     int response, ch;
347 
348     /*
349      * If the user changes the display we need memory to put it in.
350      */
351     bstring *my_data = NULL;
352     char *choices[MAXCHOICES];
353     int CurrentCharSet = current_char_set;
354     int CurrentAssumeCharSet = UCLYhndl_for_unspec;
355     int CurrentShowColor = LYShowColor;
356     BOOLEAN CurrentRawMode = LYRawMode;
357     BOOLEAN AddValueAccepted = FALSE;
358     BOOL use_assume_charset;
359 
360 #if defined(VMS) || defined(USE_SLANG)
361     BOOL old_use_assume_charset;
362 #endif
363 
364 #ifdef DIRED_SUPPORT
365 #ifdef ENABLE_OPTS_CHANGE_EXEC
366     if (LYlines < 24) {
367 	HTAlert(OPTION_SCREEN_NEEDS_24);
368 	return;
369     }
370 #else
371     if (LYlines < 23) {
372 	HTAlert(OPTION_SCREEN_NEEDS_23);
373 	return;
374     }
375 #endif /* ENABLE_OPTS_CHANGE_EXEC */
376 #else
377 #ifdef ENABLE_OPTS_CHANGE_EXEC
378     if (LYlines < 23) {
379 	HTAlert(OPTION_SCREEN_NEEDS_23);
380 	return;
381     }
382 #else
383     if (LYlines < 22) {
384 	HTAlert(OPTION_SCREEN_NEEDS_22);
385 	return;
386     }
387 #endif /* ENABLE_OPTS_CHANGE_EXEC */
388 #endif /* DIRED_SUPPORT */
389 
390     term_options = FALSE;
391     LYStatusLine = (LYlines - 1);	/* screen is otherwise too crowded */
392     signal(SIGINT, terminate_options);
393     if (no_option_save) {
394 	if (LYShowColor == SHOW_COLOR_NEVER) {
395 	    LYShowColor = SHOW_COLOR_OFF;
396 	} else if (LYShowColor == SHOW_COLOR_ALWAYS) {
397 	    LYShowColor = SHOW_COLOR_ON;
398 	}
399 #if defined(USE_SLANG) || defined(COLOR_CURSES)
400     } else {
401 	SetupChosenShowColor();
402 #endif /* USE_SLANG || COLOR_CURSES */
403     }
404 
405     use_assume_charset = (BOOLEAN) (user_mode == ADVANCED_MODE);
406 
407   draw_options:
408 
409 #if defined(VMS) || defined(USE_SLANG)
410     old_use_assume_charset = use_assume_charset;
411 #endif
412     /*
413      * NOTE that printw() should be avoided for strings that might have
414      * non-ASCII or multibyte/CJK characters.  - FM
415      */
416 #if defined(FANCY_CURSES) || defined (USE_SLANG)
417     if (enable_scrollback) {
418 	LYclear();
419     } else {
420 	LYerase();
421     }
422 #else
423     LYclear();
424 #endif /* FANCY_CURSES || USE_SLANG */
425     LYmove(0, 5);
426 
427     lynx_start_h1_color();
428     LYaddstr("         Options Menu (");
429     LYaddstr(LYNX_NAME);
430     LYaddstr(" Version ");
431     LYaddstr(LYNX_VERSION);
432     LYaddch(')');
433     lynx_stop_h1_color();
434     LYmove(L_EDITOR, 5);
435     addlbl("(E)ditor                     : ");
436     LYaddstr(non_empty(editor) ? editor : "NONE");
437 
438     LYmove(L_DISPLAY, 5);
439     addlbl("(D)ISPLAY variable           : ");
440     LYaddstr(non_empty(x_display) ? x_display : "NONE");
441 
442     LYmove(L_HOME, 5);
443     addlbl("mu(L)ti-bookmarks: ");
444     LYaddstr(mbm_choices[LYMultiBookmarks]);
445     LYmove(L_HOME, B_BOOK);
446     if (LYMultiBookmarks != MBM_OFF) {
447 	addlbl("review/edit (B)ookmarks files");
448     } else {
449 	addlbl("(B)ookmark file: ");
450 	LYaddstr(non_empty(bookmark_page) ? bookmark_page : "NONE");
451     }
452 
453     LYmove(L_FTPSTYPE, 5);
454     addlbl("(F)TP sort criteria          : ");
455     LYaddstr((HTfileSortMethod == FILE_BY_NAME ? "By Filename" :
456 	      (HTfileSortMethod == FILE_BY_SIZE ? "By Size    " :
457 	       (HTfileSortMethod == FILE_BY_TYPE ? "By Type    " :
458 		"By Date    "))));
459 
460     LYmove(L_MAIL_ADDRESS, 5);
461     addlbl("(P)ersonal mail address      : ");
462     LYaddstr(non_empty(personal_mail_address) ?
463 	     personal_mail_address : "NONE");
464 
465     LYmove(L_SSEARCH, 5);
466     addlbl("(S)earching type             : ");
467     LYaddstr(LYcase_sensitive ? "CASE SENSITIVE  " : "CASE INSENSITIVE");
468 
469     LYmove(L_Charset, 5);
470     addlbl("display (C)haracter set      : ");
471     LYaddstr(LYchar_set_names[current_char_set]);
472 
473     LYmove(L_LANGUAGE, 5);
474     addlbl("preferred document lan(G)uage: ");
475     LYaddstr(non_empty(language) ? language : "NONE");
476 
477     LYmove(L_PREF_CHARSET, 5);
478     addlbl("preferred document c(H)arset : ");
479     LYaddstr(non_empty(pref_charset) ? pref_charset : "NONE");
480 
481     if (use_assume_charset) {
482 	LYmove(L_ASSUME_CHARSET, 5);
483 	addlbl("(^A)ssume charset if unknown : ");
484 	if (UCAssume_MIMEcharset)
485 	    LYaddstr(UCAssume_MIMEcharset);
486 	else
487 	    LYaddstr((UCLYhndl_for_unspec >= 0) ?
488 		     LYCharSet_UC[UCLYhndl_for_unspec].MIMEname
489 		     : "NONE");
490     }
491 
492     LYmove(L_Rawmode, 5);
493     addlbl("Raw 8-bit or CJK m(O)de      : ");
494     ShowBool(LYRawMode);
495 
496 #if defined(USE_SLANG) || defined(COLOR_CURSES)
497     LYmove(L_Color, B_COLOR);
498     addlbl("show color (&)  : ");
499     if (no_option_save) {
500 	ShowBool(LYShowColor == SHOW_COLOR_OFF);
501     } else {
502 	switch (LYChosenShowColor) {
503 	case SHOW_COLOR_NEVER:
504 	    LYaddstr("NEVER     ");
505 	    break;
506 	case SHOW_COLOR_OFF:
507 	    LYaddstr("OFF");
508 	    break;
509 	case SHOW_COLOR_ON:
510 	    LYaddstr("ON ");
511 	    break;
512 	case SHOW_COLOR_ALWAYS:
513 #if defined(COLOR_CURSES)
514 	    if (!has_colors())
515 		LYaddstr("Always try");
516 	    else
517 #endif
518 		LYaddstr("ALWAYS    ");
519 	}
520     }
521 #endif /* USE_SLANG || COLOR_CURSES */
522 
523     LYmove(L_Bool_A, B_VIKEYS);
524     addlbl("(V)I keys: ");
525     ShowBool(vi_keys);
526 
527     LYmove(L_Bool_A, B_EMACSKEYS);
528     addlbl("e(M)acs keys: ");
529     ShowBool(emacs_keys);
530 
531     LYmove(L_Bool_A, B_SHOW_DOTFILES);
532     addlbl("sho(W) dot files: ");
533     ShowBool(!no_dotfiles && show_dotfiles);
534 
535     LYmove(L_Bool_B, B_SELECT_POPUPS);
536     addlbl("popups for selec(T) fields   : ");
537     ShowBool(LYSelectPopups);
538 
539     LYmove(L_Bool_B, B_SHOW_CURSOR);
540     addlbl("show cursor (@) : ");
541     ShowBool(LYShowCursor);
542 
543     LYmove(L_Keypad, 5);
544     addlbl("(K)eypad mode                : ");
545     LYaddstr((fields_are_numbered() && links_are_numbered())
546 	     ? "Links and form fields are numbered"
547 	     : (links_are_numbered()
548 		? "Links are numbered                "
549 		: (fields_are_numbered()
550 		   ? "Form fields are numbered          "
551 		   : "Numbers act as arrows             ")));
552 
553     LYmove(L_Lineed, 5);
554     addlbl("li(N)e edit style            : ");
555     LYaddstr(LYEditorNames[current_lineedit]);
556 
557 #ifdef EXP_KEYBOARD_LAYOUT
558     LYmove(L_Layout, 5);
559     addlbl("Ke(Y)board layout            : ");
560     LYaddstr(LYKbLayoutNames[current_layout]);
561 #endif
562 
563 #ifdef DIRED_SUPPORT
564     LYmove(L_Dired, 5);
565     addlbl("l(I)st directory style       : ");
566     LYaddstr((dir_list_style == FILES_FIRST) ? "Files first      " :
567 	     ((dir_list_style == MIXED_STYLE) ? "Mixed style      " :
568 	      "Directories first"));
569 #endif /* DIRED_SUPPORT */
570 
571     LYmove(L_User_Mode, 5);
572     addlbl("(U)ser mode                  : ");
573     LYaddstr((user_mode == NOVICE_MODE) ? "Novice      " :
574 	     ((user_mode == INTERMEDIATE_MODE) ? "Intermediate" :
575 	      "Advanced    "));
576 
577     addlbl("  verbose images (!) : ");
578     ShowBool(verbose_img);
579 
580     LYmove(L_User_Agent, 5);
581     addlbl("user (A)gent                 : ");
582     LYaddstr(non_empty(LYUserAgent) ? LYUserAgent : "NONE");
583 
584 #if defined(ENABLE_OPTS_CHANGE_EXEC) && (defined(EXEC_LINKS) || defined(EXEC_SCRIPTS))
585     LYmove(L_Exec, 5);
586     addlbl("local e(X)ecution links      : ");
587 #ifndef NEVER_ALLOW_REMOTE_EXEC
588     LYaddstr(local_exec ? "ALWAYS ON           " :
589 	     (local_exec_on_local_files ? "FOR LOCAL FILES ONLY" :
590 	      "ALWAYS OFF          "));
591 #else
592     LYaddstr(local_exec_on_local_files ? "FOR LOCAL FILES ONLY" :
593 	     "ALWAYS OFF          ");
594 #endif /* !NEVER_ALLOW_REMOTE_EXEC */
595 #endif /* ENABLE_OPTS_CHANGE_EXEC */
596 
597     LYmove(LYlines - 3, 2);
598     LYaddstr(SELECT_SEGMENT);
599     lynx_start_bold();
600     LYaddstr(CAP_LETT_SEGMENT);
601     lynx_stop_bold();
602     LYaddstr(OF_OPT_LINE_SEGMENT);
603     if (!no_option_save) {
604 	LYaddstr(" '");
605 	lynx_start_bold();
606 	LYaddstr(">");
607 	lynx_stop_bold();
608 	LYaddstr("'");
609 	LYaddstr(TO_SAVE_SEGMENT);
610     }
611     LYaddstr(OR_SEGMENT);
612     LYaddstr("'");
613     lynx_start_bold();
614     LYaddstr("r");
615     lynx_stop_bold();
616     LYaddstr("'");
617     LYaddstr(TO_RETURN_SEGMENT);
618 
619     response = 0;
620     while (response != 'R' &&
621 	   !LYisNonAlnumKeyname(response, LYK_PREV_DOC) &&
622 	   response != '>' && !term_options &&
623 	   !LYCharIsINTERRUPT_NO_letter(response)) {
624 	if (AddValueAccepted == TRUE) {
625 	    _statusline(VALUE_ACCEPTED);
626 	    AddValueAccepted = FALSE;
627 	}
628 	LYmove((LYlines - 2), 0);
629 	lynx_start_prompt_color();
630 	LYaddstr(COMMAND_PROMPT);
631 	lynx_stop_prompt_color();
632 
633 	LYrefresh();
634 	response = LYgetch_single();
635 	if (term_options || LYCharIsINTERRUPT_NO_letter(response))
636 	    response = 'R';
637 	if (LYisNonAlnumKeyname(response, LYK_REFRESH)) {
638 	    lynx_force_repaint();
639 	    goto draw_options;
640 	}
641 	switch (response) {
642 	case 'E':		/* Change the editor. */
643 	    if (no_editor) {
644 		_statusline(EDIT_DISABLED);
645 	    } else if (system_editor) {
646 		_statusline(EDITOR_LOCKED);
647 	    } else {
648 		if (non_empty(editor)) {
649 		    BStrCopy0(my_data, editor);
650 		} else {	/* clear the NONE */
651 		    LYmove(L_EDITOR, COL_OPTION_VALUES);
652 		    LYaddstr("    ");
653 		    BStrCopy0(my_data, "");
654 		}
655 		_statusline(ACCEPT_DATA);
656 		LYmove(L_EDITOR, COL_OPTION_VALUES);
657 		lynx_start_bold();
658 		ch = LYgetBString(&my_data, FALSE, 0, NORECALL);
659 		lynx_stop_bold();
660 		LYmove(L_EDITOR, COL_OPTION_VALUES);
661 		if (term_options || ch == -1) {
662 		    LYaddstr(non_empty(editor) ?
663 			     editor : "NONE");
664 		} else if (isBEmpty(my_data)) {
665 		    FREE(editor);
666 		    LYaddstr("NONE");
667 		} else {
668 		    StrAllocCopy(editor, my_data->str);
669 		    LYaddstr(editor);
670 		}
671 		LYclrtoeol();
672 		if (ch == -1) {
673 		    HTInfoMsg(CANCELLED);
674 		    HTInfoMsg("");
675 		} else {
676 		    _statusline(VALUE_ACCEPTED);
677 		}
678 	    }
679 	    response = ' ';
680 	    break;
681 
682 	case 'D':		/* Change the display. */
683 	    if (non_empty(x_display)) {
684 		BStrCopy0(my_data, x_display);
685 	    } else {		/* clear the NONE */
686 		LYmove(L_DISPLAY, COL_OPTION_VALUES);
687 		LYaddstr("    ");
688 		BStrCopy0(my_data, "");
689 	    }
690 	    _statusline(ACCEPT_DATA);
691 	    LYmove(L_DISPLAY, COL_OPTION_VALUES);
692 	    lynx_start_bold();
693 	    ch = LYgetBString(&my_data, FALSE, 0, NORECALL);
694 	    lynx_stop_bold();
695 	    LYmove(L_DISPLAY, COL_OPTION_VALUES);
696 
697 #ifdef VMS
698 #define CompareEnvVars(a,b) strcasecomp(a, b)
699 #else
700 #define CompareEnvVars(a,b) strcmp(a, b)
701 #endif /* VMS */
702 
703 	    if ((term_options || ch == -1) ||
704 		(x_display != NULL &&
705 		 !CompareEnvVars(x_display, my_data->str))) {
706 		/*
707 		 * Cancelled, or a non-NULL display string wasn't changed.  -
708 		 * FM
709 		 */
710 		LYaddstr(non_empty(x_display) ? x_display : "NONE");
711 		LYclrtoeol();
712 		if (ch == -1) {
713 		    HTInfoMsg(CANCELLED);
714 		    HTInfoMsg("");
715 		} else {
716 		    _statusline(VALUE_ACCEPTED);
717 		}
718 		response = ' ';
719 		break;
720 	    } else if (isBEmpty(my_data)) {
721 		if ((x_display == NULL) ||
722 		    (x_display != NULL && *x_display == '\0')) {
723 		    /*
724 		     * NULL or zero-length display string wasn't changed.  - FM
725 		     */
726 		    LYaddstr("NONE");
727 		    LYclrtoeol();
728 		    _statusline(VALUE_ACCEPTED);
729 		    response = ' ';
730 		    break;
731 		}
732 	    }
733 	    /*
734 	     * Set the new DISPLAY variable.  - FM
735 	     */
736 	    LYsetXDisplay(my_data->str);
737 	    validate_x_display();
738 	    LYaddstr(x_display ? x_display : "NONE");
739 	    LYclrtoeol();
740 	    summarize_x_display(my_data->str);
741 	    response = ' ';
742 	    break;
743 
744 	case 'L':		/* Change multibookmarks option. */
745 	    if (LYMBMBlocked) {
746 		_statusline(MULTIBOOKMARKS_DISALLOWED);
747 		response = ' ';
748 		break;
749 	    }
750 	    if (!LYSelectPopups) {
751 		LYMultiBookmarks = LYChooseEnum(LYMultiBookmarks,
752 						L_HOME, C_MULTI,
753 						mbm_choices);
754 	    } else {
755 		LYMultiBookmarks = LYChoosePopup(LYMultiBookmarks,
756 						 L_HOME, (C_MULTI - 1),
757 						 mbm_choices,
758 						 3, FALSE, FALSE);
759 	    }
760 #if defined(VMS) || defined(USE_SLANG)
761 	    if (LYSelectPopups) {
762 		LYmove(L_HOME, C_MULTI);
763 		LYclrtoeol();
764 		LYaddstr(mbm_choices[LYMultiBookmarks]);
765 	    }
766 #endif /* VMS || USE_SLANG */
767 #if !defined(VMS) && !defined(USE_SLANG)
768 	    if (!LYSelectPopups)
769 #endif /* !VMS && !USE_SLANG */
770 	    {
771 		LYmove(L_HOME, B_BOOK);
772 		LYclrtoeol();
773 		if (LYMultiBookmarks != MBM_OFF) {
774 		    LYaddstr(gettext("review/edit B)ookmarks files"));
775 		} else {
776 		    LYaddstr(gettext("B)ookmark file: "));
777 		    LYaddstr(non_empty(bookmark_page) ?
778 			     bookmark_page : "NONE");
779 		}
780 	    }
781 	    response = ' ';
782 	    if (LYSelectPopups) {
783 		HANDLE_LYOPTIONS;
784 	    }
785 	    break;
786 
787 	case 'B':		/* Change the bookmark page location. */
788 	    /*
789 	     * Anonymous users should not be allowed to change the bookmark
790 	     * page.
791 	     */
792 	    if (!no_bookmark) {
793 		if (LYMultiBookmarks != MBM_OFF) {
794 		    edit_bookmarks();
795 		    signal(SIGINT, terminate_options);
796 		    goto draw_options;
797 		}
798 		if (non_empty(bookmark_page)) {
799 		    BStrCopy0(my_data, bookmark_page);
800 		} else {	/* clear the NONE */
801 		    LYmove(L_HOME, C_DEFAULT);
802 		    LYclrtoeol();
803 		    BStrCopy0(my_data, "");
804 		}
805 		_statusline(ACCEPT_DATA);
806 		LYmove(L_HOME, C_DEFAULT);
807 		lynx_start_bold();
808 		ch = LYgetBString(&my_data, FALSE, 0, NORECALL);
809 		lynx_stop_bold();
810 		LYmove(L_HOME, C_DEFAULT);
811 		BStrAlloc(my_data, my_data->len + LY_MAXPATH);	/* lengthen */
812 		if (term_options ||
813 		    ch == -1 || isBEmpty(my_data)) {
814 		    LYaddstr(non_empty(bookmark_page) ?
815 			     bookmark_page : "NONE");
816 		} else if (!LYPathOffHomeOK(my_data->str, (size_t) my_data->len)) {
817 		    LYaddstr(non_empty(bookmark_page) ?
818 			     bookmark_page : "NONE");
819 		    LYclrtoeol();
820 		    _statusline(USE_PATH_OFF_HOME);
821 		    response = ' ';
822 		    break;
823 		} else {
824 		    StrAllocCopy(bookmark_page, my_data->str);
825 		    StrAllocCopy(MBM_A_subbookmark[0], bookmark_page);
826 		    LYaddstr(bookmark_page);
827 		}
828 		LYclrtoeol();
829 		if (ch == -1) {
830 		    HTInfoMsg(CANCELLED);
831 		    HTInfoMsg("");
832 		} else {
833 		    _statusline(VALUE_ACCEPTED);
834 		}
835 	    } else {		/* anonymous */
836 		_statusline(BOOKMARK_CHANGE_DISALLOWED);
837 	    }
838 	    response = ' ';
839 	    break;
840 
841 	case 'F':		/* Change ftp directory sorting. */
842 	    if (!LYSelectPopups) {
843 		HTfileSortMethod = LYChooseEnum(HTfileSortMethod,
844 						L_FTPSTYPE, -1,
845 						fileSort_choices);
846 	    } else {
847 		HTfileSortMethod = LYChoosePopup(HTfileSortMethod,
848 						 L_FTPSTYPE, -1,
849 						 fileSort_choices,
850 						 4, FALSE, FALSE);
851 #if defined(VMS) || defined(USE_SLANG)
852 		LYmove(L_FTPSTYPE, COL_OPTION_VALUES);
853 		LYclrtoeol();
854 		LYaddstr(fileSort_choices[HTfileSortMethod]);
855 #endif /* VMS || USE_SLANG */
856 	    }
857 	    response = ' ';
858 	    if (LYSelectPopups) {
859 		HANDLE_LYOPTIONS;
860 	    }
861 	    break;
862 
863 	case 'P':		/* Change personal mail address for From headers. */
864 	    if (non_empty(personal_mail_address)) {
865 		BStrCopy0(my_data, personal_mail_address);
866 	    } else {		/* clear the NONE */
867 		LYmove(L_MAIL_ADDRESS, COL_OPTION_VALUES);
868 		LYaddstr("    ");
869 		BStrCopy0(my_data, "");
870 	    }
871 	    _statusline(ACCEPT_DATA);
872 	    LYmove(L_MAIL_ADDRESS, COL_OPTION_VALUES);
873 	    lynx_start_bold();
874 	    ch = LYgetBString(&my_data, FALSE, 0, NORECALL);
875 	    lynx_stop_bold();
876 	    LYmove(L_MAIL_ADDRESS, COL_OPTION_VALUES);
877 	    if (term_options || ch == -1) {
878 		LYaddstr((personal_mail_address &&
879 			  *personal_mail_address) ?
880 			 personal_mail_address : "NONE");
881 	    } else if (isBEmpty(my_data)) {
882 		FREE(personal_mail_address);
883 		LYaddstr("NONE");
884 	    } else {
885 		StrAllocCopy(personal_mail_address, my_data->str);
886 		LYaddstr(personal_mail_address);
887 	    }
888 	    LYclrtoeol();
889 	    if (ch == -1) {
890 		HTInfoMsg(CANCELLED);
891 		HTInfoMsg("");
892 	    } else {
893 		_statusline(VALUE_ACCEPTED);
894 	    }
895 	    response = ' ';
896 	    break;
897 
898 	case 'S':		/* Change case sensitivity for searches. */
899 	    LYcase_sensitive = LYChooseBoolean(LYcase_sensitive,
900 					       L_SSEARCH, -1,
901 					       caseless_choices);
902 	    response = ' ';
903 	    break;
904 
905 	case '\001':		/* Change assume_charset setting. */
906 	    if (use_assume_charset) {
907 		int i, curval;
908 		const char **assume_list;
909 		assume_list = typecallocn(const char *, (unsigned)
910 					    (LYNumCharsets + 1));
911 
912 		if (!assume_list) {
913 		    outofmem(__FILE__, "options");
914 		}
915 		for (i = 0; i < LYNumCharsets; i++) {
916 		    assume_list[i] = LYCharSet_UC[i].MIMEname;
917 		}
918 		curval = UCLYhndl_for_unspec;
919 		if (curval == current_char_set && UCAssume_MIMEcharset) {
920 		    curval = UCGetLYhndl_byMIME(UCAssume_MIMEcharset);
921 		}
922 		if (curval < 0)
923 		    curval = LYRawMode ? current_char_set : 0;
924 		if (!LYSelectPopups) {
925 #ifndef ALL_CHARSETS_IN_O_MENU_SCREEN
926 		    UCLYhndl_for_unspec =
927 			assumed_doc_charset_map[(LYChooseEnum(charset_subsets[curval].assumed_idx,
928 							      L_ASSUME_CHARSET, -1,
929 							      assumed_charset_choices)
930 						 ? 1
931 						 : 0)];
932 #else
933 		    UCLYhndl_for_unspec =
934 			LYChooseEnum(curval,
935 				     L_ASSUME_CHARSET, -1,
936 				     assume_list);
937 #endif
938 		} else {
939 #ifndef ALL_CHARSETS_IN_O_MENU_SCREEN
940 		    UCLYhndl_for_unspec =
941 			assumed_doc_charset_map[(LYChoosePopup(charset_subsets[curval].assumed_idx,
942 							       L_ASSUME_CHARSET, -1,
943 							       assumed_charset_choices,
944 							       0,
945 							       FALSE,
946 							       FALSE)
947 						 ? 1
948 						 : 0)];
949 #else
950 		    UCLYhndl_for_unspec =
951 			LYChoosePopup(curval,
952 				      L_ASSUME_CHARSET, -1,
953 				      assume_list,
954 				      0, FALSE, FALSE);
955 #endif
956 #if defined(VMS) || defined(USE_SLANG)
957 		    LYmove(L_ASSUME_CHARSET, COL_OPTION_VALUES);
958 		    LYclrtoeol();
959 		    if (UCLYhndl_for_unspec >= 0)
960 			LYaddstr(LYCharSet_UC[UCLYhndl_for_unspec].MIMEname);
961 #endif /* VMS || USE_SLANG */
962 		}
963 
964 		/*
965 		 * Set the raw 8-bit or CJK mode defaults and character set if
966 		 * changed.  - FM
967 		 */
968 		if (CurrentAssumeCharSet != UCLYhndl_for_unspec ||
969 		    UCLYhndl_for_unspec != curval) {
970 		    if (UCLYhndl_for_unspec != CurrentAssumeCharSet) {
971 			StrAllocCopy(UCAssume_MIMEcharset,
972 				     LYCharSet_UC[UCLYhndl_for_unspec].MIMEname);
973 		    }
974 		    if (HTCJK != JAPANESE)
975 			LYRawMode = (BOOLEAN) (UCLYhndl_for_unspec == current_char_set);
976 		    HTMLSetUseDefaultRawMode(current_char_set, LYRawMode);
977 		    HTMLSetCharacterHandling(current_char_set);
978 		    CurrentAssumeCharSet = UCLYhndl_for_unspec;
979 		    CurrentRawMode = LYRawMode;
980 #if !defined(VMS) && !defined(USE_SLANG)
981 		    if (!LYSelectPopups)
982 #endif /* !VMS && !USE_SLANG */
983 		    {
984 			LYmove(L_RAWMODE + 1, COL_OPTION_VALUES);
985 			LYclrtoeol();
986 			ShowBool(LYRawMode);
987 		    }
988 		}
989 		FREE(assume_list);
990 		response = ' ';
991 		if (LYSelectPopups) {
992 		    HANDLE_LYOPTIONS;
993 		}
994 	    } else {
995 		_statusline(NEED_ADVANCED_USER_MODE);
996 		AddValueAccepted = FALSE;
997 	    }
998 	    break;
999 
1000 	case 'C':		/* Change display charset setting. */
1001 	    if (!LYSelectPopups) {
1002 #ifndef ALL_CHARSETS_IN_O_MENU_SCREEN
1003 		displayed_display_charset_idx = LYChooseEnum(displayed_display_charset_idx,
1004 							     L_Charset, -1,
1005 							     display_charset_choices);
1006 		current_char_set = display_charset_map[displayed_display_charset_idx];
1007 #else
1008 		current_char_set = LYChooseEnum(current_char_set,
1009 						L_Charset, -1,
1010 						LYchar_set_names);
1011 #endif
1012 	    } else {
1013 #ifndef ALL_CHARSETS_IN_O_MENU_SCREEN
1014 		displayed_display_charset_idx = LYChoosePopup(displayed_display_charset_idx,
1015 							      L_Charset, -1,
1016 							      display_charset_choices,
1017 							      0, FALSE, FALSE);
1018 		current_char_set = display_charset_map[displayed_display_charset_idx];
1019 #else
1020 		current_char_set = LYChoosePopup(current_char_set,
1021 						 L_Charset, -1,
1022 						 LYchar_set_names,
1023 						 0, FALSE, FALSE);
1024 #endif
1025 
1026 #if defined(VMS) || defined(USE_SLANG)
1027 		LYmove(L_Charset, COL_OPTION_VALUES);
1028 		LYclrtoeol();
1029 		LYaddstr(LYchar_set_names[current_char_set]);
1030 #endif /* VMS || USE_SLANG */
1031 	    }
1032 	    /*
1033 	     * Set the raw 8-bit or CJK mode defaults and character set if
1034 	     * changed.  - FM
1035 	     */
1036 	    if (CurrentCharSet != current_char_set) {
1037 		LYUseDefaultRawMode = TRUE;
1038 		HTMLUseCharacterSet(current_char_set);
1039 		CurrentCharSet = current_char_set;
1040 		CurrentRawMode = LYRawMode;
1041 #if !defined(VMS) && !defined(USE_SLANG)
1042 		if (!LYSelectPopups)
1043 #endif /* !VMS && !USE_SLANG */
1044 		{
1045 		    LYmove(L_Rawmode, COL_OPTION_VALUES);
1046 		    LYclrtoeol();
1047 		    ShowBool(LYRawMode);
1048 		}
1049 #ifdef CAN_SWITCH_DISPLAY_CHARSET
1050 		/* Deduce whether the user wants autoswitch: */
1051 		switch_display_charsets =
1052 		    (current_char_set == auto_display_charset
1053 		     || current_char_set == auto_other_display_charset);
1054 #endif
1055 	    }
1056 	    response = ' ';
1057 	    if (LYSelectPopups) {
1058 		HANDLE_LYOPTIONS;
1059 	    }
1060 	    break;
1061 
1062 	case 'O':		/* Change raw mode setting. */
1063 	    LYRawMode = LYChooseBoolean(LYRawMode, L_Rawmode, -1, bool_choices);
1064 	    /*
1065 	     * Set the LYUseDefaultRawMode value and character handling if
1066 	     * LYRawMode was changed.  - FM
1067 	     */
1068 	    if (CurrentRawMode != LYRawMode) {
1069 		HTMLSetUseDefaultRawMode(current_char_set, LYRawMode);
1070 		HTMLSetCharacterHandling(current_char_set);
1071 		CurrentRawMode = LYRawMode;
1072 	    }
1073 	    response = ' ';
1074 	    break;
1075 
1076 	case 'G':		/* Change language preference. */
1077 	    if (non_empty(language)) {
1078 		BStrCopy0(my_data, language);
1079 	    } else {		/* clear the NONE */
1080 		LYmove(L_LANGUAGE, COL_OPTION_VALUES);
1081 		LYaddstr("    ");
1082 		BStrCopy0(my_data, "");
1083 	    }
1084 	    _statusline(ACCEPT_DATA);
1085 	    LYmove(L_LANGUAGE, COL_OPTION_VALUES);
1086 	    lynx_start_bold();
1087 	    ch = LYgetBString(&my_data, FALSE, 0, NORECALL);
1088 	    lynx_stop_bold();
1089 	    LYmove(L_LANGUAGE, COL_OPTION_VALUES);
1090 	    if (term_options || ch == -1) {
1091 		LYaddstr(non_empty(language) ?
1092 			 language : "NONE");
1093 	    } else if (isBEmpty(my_data)) {
1094 		FREE(language);
1095 		LYaddstr("NONE");
1096 	    } else {
1097 		StrAllocCopy(language, my_data->str);
1098 		LYaddstr(language);
1099 	    }
1100 	    LYclrtoeol();
1101 	    if (ch == -1) {
1102 		HTInfoMsg(CANCELLED);
1103 		HTInfoMsg("");
1104 	    } else {
1105 		_statusline(VALUE_ACCEPTED);
1106 	    }
1107 	    response = ' ';
1108 	    break;
1109 
1110 	case 'H':		/* Change charset preference. */
1111 	    if (non_empty(pref_charset)) {
1112 		BStrCopy0(my_data, pref_charset);
1113 	    } else {		/* clear the NONE */
1114 		LYmove(L_PREF_CHARSET, COL_OPTION_VALUES);
1115 		LYaddstr("    ");
1116 		BStrCopy0(my_data, "");
1117 	    }
1118 	    _statusline(ACCEPT_DATA);
1119 	    LYmove(L_PREF_CHARSET, COL_OPTION_VALUES);
1120 	    lynx_start_bold();
1121 	    ch = LYgetBString(&my_data, FALSE, 0, NORECALL);
1122 	    lynx_stop_bold();
1123 	    LYmove(L_PREF_CHARSET, COL_OPTION_VALUES);
1124 	    if (term_options || ch == -1) {
1125 		LYaddstr(non_empty(pref_charset) ?
1126 			 pref_charset : "NONE");
1127 	    } else if (isBEmpty(my_data)) {
1128 		FREE(pref_charset);
1129 		LYaddstr("NONE");
1130 	    } else {
1131 		StrAllocCopy(pref_charset, my_data->str);
1132 		LYaddstr(pref_charset);
1133 	    }
1134 	    LYclrtoeol();
1135 	    if (ch == -1) {
1136 		HTInfoMsg(CANCELLED);
1137 		HTInfoMsg("");
1138 	    } else {
1139 		_statusline(VALUE_ACCEPTED);
1140 	    }
1141 	    response = ' ';
1142 	    break;
1143 
1144 	case 'V':		/* Change VI keys setting. */
1145 	    vi_keys = LYChooseBoolean(vi_keys,
1146 				      L_Bool_A, C_VIKEYS,
1147 				      bool_choices);
1148 	    if (vi_keys) {
1149 		set_vi_keys();
1150 	    } else {
1151 		reset_vi_keys();
1152 	    }
1153 	    response = ' ';
1154 	    break;
1155 
1156 	case 'M':		/* Change emacs keys setting. */
1157 	    emacs_keys = LYChooseBoolean(emacs_keys,
1158 					 L_Bool_A, C_EMACSKEYS,
1159 					 bool_choices);
1160 	    if (emacs_keys) {
1161 		set_emacs_keys();
1162 	    } else {
1163 		reset_emacs_keys();
1164 	    }
1165 	    response = ' ';
1166 	    break;
1167 
1168 	case 'W':		/* Change show dotfiles setting. */
1169 	    if (no_dotfiles) {
1170 		_statusline(DOTFILE_ACCESS_DISABLED);
1171 	    } else {
1172 		show_dotfiles = LYChooseBoolean(show_dotfiles,
1173 						L_Bool_A,
1174 						C_SHOW_DOTFILES,
1175 						bool_choices);
1176 	    }
1177 	    response = ' ';
1178 	    break;
1179 
1180 	case 'T':		/* Change select popups setting. */
1181 	    LYSelectPopups = LYChooseBoolean(LYSelectPopups,
1182 					     L_Bool_B,
1183 					     C_SELECT_POPUPS,
1184 					     bool_choices);
1185 	    response = ' ';
1186 	    break;
1187 
1188 #if defined(USE_SLANG) || defined(COLOR_CURSES)
1189 	case '&':		/* Change show color setting. */
1190 	    if (no_option_save) {
1191 #if defined(COLOR_CURSES)
1192 		if (!has_colors()) {
1193 		    char *terminal = LYGetEnv("TERM");
1194 
1195 		    if (terminal)
1196 			HTUserMsg2(COLOR_TOGGLE_DISABLED_FOR_TERM,
1197 				   terminal);
1198 		    else
1199 			HTUserMsg(COLOR_TOGGLE_DISABLED);
1200 		    break;
1201 		}
1202 #endif
1203 		LYShowColor = LYChooseEnum((LYShowColor - 1),
1204 					   L_Color,
1205 					   C_COLOR,
1206 					   bool_choices);
1207 		if (LYShowColor == 0) {
1208 		    LYShowColor = SHOW_COLOR_OFF;
1209 		} else {
1210 		    LYShowColor = SHOW_COLOR_ON;
1211 		}
1212 	    } else {		/* !no_option_save */
1213 		BOOLEAN again = FALSE;
1214 		int chosen;
1215 
1216 		/*
1217 		 * Copy strings into choice array.
1218 		 */
1219 		choices[0] = NULL;
1220 		StrAllocCopy(choices[0], "NEVER     ");
1221 		choices[1] = NULL;
1222 		StrAllocCopy(choices[1], "OFF       ");
1223 		choices[2] = NULL;
1224 		StrAllocCopy(choices[2], "ON        ");
1225 		choices[3] = NULL;
1226 #if defined(COLOR_CURSES)
1227 		if (!has_colors())
1228 		    StrAllocCopy(choices[3], "Always try");
1229 		else
1230 #endif
1231 		    StrAllocCopy(choices[3], "ALWAYS    ");
1232 		choices[4] = NULL;
1233 		do {
1234 		    if (!LYSelectPopups) {
1235 			chosen = LYChooseEnum(LYChosenShowColor,
1236 					      L_Color,
1237 					      C_COLOR,
1238 					      choices);
1239 		    } else {
1240 			chosen = LYChoosePopup(LYChosenShowColor,
1241 					       L_Color,
1242 					       C_COLOR,
1243 					       choices, 4, FALSE, FALSE);
1244 		    }
1245 #if defined(COLOR_CURSES)
1246 		    again = (BOOLEAN) (chosen == SHOW_COLOR_ON && !has_colors());
1247 		    if (again) {
1248 			char *terminal = LYGetEnv("TERM");
1249 
1250 			if (terminal)
1251 			    HTUserMsg2(COLOR_TOGGLE_DISABLED_FOR_TERM,
1252 				       terminal);
1253 			else
1254 			    HTUserMsg(COLOR_TOGGLE_DISABLED);
1255 		    }
1256 #endif
1257 		} while (again);
1258 		LYChosenShowColor = chosen;
1259 #if defined(VMS)
1260 		if (LYSelectPopups) {
1261 		    LYmove(L_Color, C_COLOR);
1262 		    LYclrtoeol();
1263 		    LYaddstr(choices[LYChosenShowColor]);
1264 		}
1265 #endif /* VMS */
1266 #if defined(COLOR_CURSES)
1267 		if (has_colors())
1268 #endif
1269 		    LYShowColor = chosen;
1270 		FREE(choices[0]);
1271 		FREE(choices[1]);
1272 		FREE(choices[2]);
1273 		FREE(choices[3]);
1274 	    }
1275 	    if (CurrentShowColor != LYShowColor) {
1276 		lynx_force_repaint();
1277 	    }
1278 	    CurrentShowColor = LYShowColor;
1279 #ifdef USE_SLANG
1280 	    SLtt_Use_Ansi_Colors = (LYShowColor > SHOW_COLOR_OFF ? TRUE : FALSE);
1281 #endif
1282 	    response = ' ';
1283 	    if (LYSelectPopups && !no_option_save) {
1284 		HANDLE_LYOPTIONS;
1285 	    }
1286 	    break;
1287 #endif /* USE_SLANG or COLOR_CURSES */
1288 
1289 	case '@':		/* Change show cursor setting. */
1290 	    LYShowCursor = LYChooseBoolean(LYShowCursor,
1291 					   L_Bool_B,
1292 					   C_SHOW_CURSOR,
1293 					   bool_choices);
1294 	    response = ' ';
1295 	    break;
1296 
1297 	case 'K':		/* Change keypad mode. */
1298 	    if (!LYSelectPopups) {
1299 		keypad_mode = LYChooseEnum(keypad_mode,
1300 					   L_Keypad, -1,
1301 					   keypad_choices);
1302 	    } else {
1303 		keypad_mode = LYChoosePopup(keypad_mode,
1304 					    L_Keypad, -1,
1305 					    keypad_choices,
1306 					    3, FALSE, FALSE);
1307 #if defined(VMS) || defined(USE_SLANG)
1308 		LYmove(L_Keypad, COL_OPTION_VALUES);
1309 		LYclrtoeol();
1310 		LYaddstr(keypad_choices[keypad_mode]);
1311 #endif /* VMS || USE_SLANG */
1312 	    }
1313 	    if (keypad_mode == NUMBERS_AS_ARROWS) {
1314 		set_numbers_as_arrows();
1315 	    } else {
1316 		reset_numbers_as_arrows();
1317 	    }
1318 	    response = ' ';
1319 	    if (LYSelectPopups) {
1320 		HANDLE_LYOPTIONS;
1321 	    }
1322 	    break;
1323 
1324 	case 'N':		/* Change line editor key bindings. */
1325 	    if (!LYSelectPopups) {
1326 		current_lineedit = LYChooseEnum(current_lineedit,
1327 						L_Lineed, -1,
1328 						LYEditorNames);
1329 	    } else {
1330 		current_lineedit = LYChoosePopup(current_lineedit,
1331 						 L_Lineed, -1,
1332 						 LYEditorNames,
1333 						 0, FALSE, FALSE);
1334 #if defined(VMS) || defined(USE_SLANG)
1335 		LYmove(L_Lineed, COL_OPTION_VALUES);
1336 		LYclrtoeol();
1337 		LYaddstr(LYEditorNames[current_lineedit]);
1338 #endif /* VMS || USE_SLANG */
1339 	    }
1340 	    response = ' ';
1341 	    if (LYSelectPopups) {
1342 		HANDLE_LYOPTIONS;
1343 	    }
1344 	    break;
1345 
1346 #ifdef EXP_KEYBOARD_LAYOUT
1347 	case 'Y':		/* Change keyboard layout */
1348 	    if (!LYSelectPopups) {
1349 		current_layout = LYChooseEnum(current_layout,
1350 					      L_Layout, -1,
1351 					      LYKbLayoutNames);
1352 	    } else {
1353 		current_layout = LYChoosePopup(current_layout,
1354 					       L_Layout, -1,
1355 					       LYKbLayoutNames,
1356 					       0, FALSE, FALSE);
1357 #if defined(VMS) || defined(USE_SLANG)
1358 		LYmove(L_Layout, COL_OPTION_VALUES);
1359 		LYclrtoeol();
1360 		LYaddstr(LYKbLayoutNames[current_layout]);
1361 #endif /* VMS || USE_SLANG */
1362 	    }
1363 	    response = ' ';
1364 	    if (LYSelectPopups) {
1365 		HANDLE_LYOPTIONS;
1366 	    }
1367 	    break;
1368 #endif /* EXP_KEYBOARD_LAYOUT */
1369 
1370 #ifdef DIRED_SUPPORT
1371 	case 'I':		/* Change local directory sorting. */
1372 	    if (!LYSelectPopups) {
1373 		dir_list_style = LYChooseEnum(dir_list_style,
1374 					      L_Dired, -1,
1375 					      dirList_choices);
1376 	    } else {
1377 		dir_list_style = LYChoosePopup(dir_list_style,
1378 					       L_Dired, -1,
1379 					       dirList_choices,
1380 					       3, FALSE, FALSE);
1381 #if defined(VMS) || defined(USE_SLANG)
1382 		LYmove(L_Dired, COL_OPTION_VALUES);
1383 		LYclrtoeol();
1384 		LYaddstr(dirList_choices[dir_list_style]);
1385 #endif /* VMS || USE_SLANG */
1386 	    }
1387 	    response = ' ';
1388 	    if (LYSelectPopups) {
1389 		HANDLE_LYOPTIONS;
1390 	    }
1391 	    break;
1392 #endif /* DIRED_SUPPORT */
1393 
1394 	case 'U':		/* Change user mode. */
1395 	    if (!LYSelectPopups) {
1396 		user_mode = LYChooseEnum(user_mode,
1397 					 L_User_Mode, -1,
1398 					 userMode_choices);
1399 		use_assume_charset = (BOOLEAN) (user_mode >= 2);
1400 	    } else {
1401 		user_mode = LYChoosePopup(user_mode,
1402 					  L_User_Mode, -1,
1403 					  userMode_choices,
1404 					  3, FALSE, FALSE);
1405 		use_assume_charset = (BOOLEAN) (user_mode >= 2);
1406 #if defined(VMS) || defined(USE_SLANG)
1407 		if (use_assume_charset == old_use_assume_charset) {
1408 		    LYmove(L_User_Mode, COL_OPTION_VALUES);
1409 		    LYclrtoeol();
1410 		    LYaddstr(userMode_choices[user_mode]);
1411 		}
1412 #endif /* VMS || USE_SLANG */
1413 	    }
1414 	    LYSetDisplayLines();
1415 	    response = ' ';
1416 	    if (LYSelectPopups) {
1417 		HANDLE_LYOPTIONS;
1418 	    }
1419 	    break;
1420 
1421 	case '!':
1422 	    if (!LYSelectPopups) {
1423 		verbose_img = LYChooseBoolean(verbose_img,
1424 					      L_VERBOSE_IMAGES,
1425 					      C_VERBOSE_IMAGES,
1426 					      bool_choices);
1427 	    } else {
1428 		verbose_img = (BOOLEAN) LYChoosePopup(verbose_img,
1429 						      L_VERBOSE_IMAGES,
1430 						      C_VERBOSE_IMAGES,
1431 						      bool_choices,
1432 						      2, FALSE, FALSE);
1433 	    }
1434 	    response = ' ';
1435 	    if (LYSelectPopups) {
1436 		HANDLE_LYOPTIONS;
1437 	    }
1438 	    break;
1439 
1440 	case 'A':		/* Change user agent string. */
1441 	    if (!no_useragent) {
1442 		if (non_empty(LYUserAgent)) {
1443 		    BStrCopy0(my_data, LYUserAgent);
1444 		} else {	/* clear the NONE */
1445 		    LYmove(L_HOME, COL_OPTION_VALUES);
1446 		    LYaddstr("    ");
1447 		    BStrCopy0(my_data, "");
1448 		}
1449 		_statusline(ACCEPT_DATA_OR_DEFAULT);
1450 		LYmove(L_User_Agent, COL_OPTION_VALUES);
1451 		lynx_start_bold();
1452 		ch = LYgetBString(&my_data, FALSE, 0, NORECALL);
1453 		lynx_stop_bold();
1454 		LYmove(L_User_Agent, COL_OPTION_VALUES);
1455 		if (term_options || ch == -1) {
1456 		    LYaddstr((LYUserAgent &&
1457 			      *LYUserAgent) ?
1458 			     LYUserAgent : "NONE");
1459 		} else if (isBEmpty(my_data)) {
1460 		    StrAllocCopy(LYUserAgent, LYUserAgentDefault);
1461 		    LYaddstr((LYUserAgent &&
1462 			      *LYUserAgent) ?
1463 			     LYUserAgent : "NONE");
1464 		} else {
1465 		    StrAllocCopy(LYUserAgent, my_data->str);
1466 		    LYaddstr(LYUserAgent);
1467 		}
1468 		LYclrtoeol();
1469 		if (ch == -1) {
1470 		    HTInfoMsg(CANCELLED);
1471 		    HTInfoMsg("");
1472 		} else if (!LYCheckUserAgent()) {
1473 		    _statusline(UA_PLEASE_USE_LYNX);
1474 		} else {
1475 		    _statusline(VALUE_ACCEPTED);
1476 		}
1477 	    } else {		/* disallowed */
1478 		_statusline(UA_CHANGE_DISABLED);
1479 	    }
1480 	    response = ' ';
1481 	    break;
1482 
1483 #if defined(ENABLE_OPTS_CHANGE_EXEC) && (defined(EXEC_LINKS) || defined(EXEC_SCRIPTS))
1484 	case 'X':		/* Change local exec restriction. */
1485 	    if (exec_frozen && !LYSelectPopups) {
1486 		_statusline(CHANGE_OF_SETTING_DISALLOWED);
1487 		response = ' ';
1488 		break;
1489 	    }
1490 #ifndef NEVER_ALLOW_REMOTE_EXEC
1491 	    if (local_exec) {
1492 		itmp = 2;
1493 	    } else
1494 #endif /* !NEVER_ALLOW_REMOTE_EXEC */
1495 	    {
1496 		if (local_exec_on_local_files) {
1497 		    itmp = 1;
1498 		} else {
1499 		    itmp = 0;
1500 		}
1501 	    }
1502 	    if (!LYSelectPopups) {
1503 		itmp = LYChooseEnum(itmp,
1504 				    L_Exec, -1,
1505 				    exec_choices);
1506 	    } else {
1507 		itmp = LYChoosePopup(itmp,
1508 				     L_Exec, -1,
1509 				     exec_choices,
1510 				     0, (exec_frozen ? TRUE : FALSE),
1511 				     FALSE);
1512 #if defined(VMS) || defined(USE_SLANG)
1513 		LYmove(L_Exec, COL_OPTION_VALUES);
1514 		LYclrtoeol();
1515 		LYaddstr(exec_choices[itmp]);
1516 #endif /* VMS || USE_SLANG */
1517 	    }
1518 	    if (!exec_frozen) {
1519 		switch (itmp) {
1520 		case 0:
1521 		    local_exec = FALSE;
1522 		    local_exec_on_local_files = FALSE;
1523 		    break;
1524 		case 1:
1525 		    local_exec = FALSE;
1526 		    local_exec_on_local_files = TRUE;
1527 		    break;
1528 #ifndef NEVER_ALLOW_REMOTE_EXEC
1529 		case 2:
1530 		    local_exec = TRUE;
1531 		    local_exec_on_local_files = FALSE;
1532 		    break;
1533 #endif /* !NEVER_ALLOW_REMOTE_EXEC */
1534 		}		/* end switch */
1535 	    }
1536 	    response = ' ';
1537 	    if (LYSelectPopups) {
1538 		HANDLE_LYOPTIONS;
1539 	    }
1540 	    break;
1541 #endif /* ENABLE_OPTS_CHANGE_EXEC */
1542 
1543 	case '>':		/* Save current options to RC file. */
1544 	    if (!no_option_save) {
1545 		HTInfoMsg(SAVING_OPTIONS);
1546 		LYrcShowColor = LYChosenShowColor;
1547 		if (save_rc(NULL)) {
1548 		    HTInfoMsg(OPTIONS_SAVED);
1549 		} else {
1550 		    HTAlert(OPTIONS_NOT_SAVED);
1551 		}
1552 	    } else {
1553 		HTInfoMsg(R_TO_RETURN_TO_LYNX);
1554 		/*
1555 		 * Change response so that we don't exit the options menu.
1556 		 */
1557 		response = ' ';
1558 	    }
1559 	    break;
1560 
1561 	case 'R':		/* Return to document (quit options menu). */
1562 	    break;
1563 
1564 	default:
1565 	    if (!no_option_save) {
1566 		HTInfoMsg(SAVE_OR_R_TO_RETURN_TO_LYNX);
1567 	    } else {
1568 		HTInfoMsg(R_TO_RETURN_TO_LYNX);
1569 	    }
1570 	}			/* end switch */
1571     }				/* end while */
1572 
1573     term_options = FALSE;
1574     LYStatusLine = -1;		/* let user_mode have some of the screen */
1575     signal(SIGINT, cleanup_sig);
1576     BStrFree(my_data);
1577     return;
1578 }
1579 
widest_choice(STRING2PTR choices)1580 static int widest_choice(STRING2PTR choices)
1581 {
1582     int n, width = 0;
1583 
1584     for (n = 0; choices[n] != NULL; ++n) {
1585 	int len = (int) strlen(choices[n]);
1586 
1587 	if (width < len)
1588 	    width = len;
1589     }
1590     return width;
1591 }
1592 
show_choice(const char * choice,int width)1593 static void show_choice(const char *choice,
1594 			int width)
1595 {
1596     int len = 0;
1597 
1598     if (choice != 0) {
1599 	len = (int) strlen(choice);
1600 
1601 	LYaddstr(choice);
1602     }
1603     while (len++ < width)
1604 	LYaddch(' ');
1605 }
1606 
1607 /*
1608  * Take a status code, prompt the user for a new status, and return it.
1609  */
boolean_choice(int cur_choice,int line,int column,STRING2PTR choices)1610 static int boolean_choice(int cur_choice,
1611 			  int line,
1612 			  int column,
1613 			  STRING2PTR choices)
1614 {
1615     int response = 0;
1616     int cmd = 0;
1617     int number = 0;
1618     int col = (column >= 0 ? column : COL_OPTION_VALUES);
1619     int orig_choice = cur_choice;
1620     int width = widest_choice(choices);
1621 
1622     /*
1623      * Get the number of choices and then make number zero-based.
1624      */
1625     for (number = 0; choices[number] != NULL; number++) ;	/* empty loop body */
1626     number--;
1627 
1628     /*
1629      * Update the statusline.
1630      */
1631     _statusline(ANY_KEY_CHANGE_RET_ACCEPT);
1632 
1633     /*
1634      * Highlight the current choice.
1635      */
1636     LYmove(line, col);
1637     lynx_start_reverse();
1638     show_choice(choices[cur_choice], width);
1639     if (LYShowCursor)
1640 	LYmove(line, (col - 1));
1641     LYrefresh();
1642 
1643     /*
1644      * Get the keyboard entry, and leave the cursor at the choice, to indicate
1645      * that it can be changed, until the user accepts the current choice.
1646      */
1647     term_options = FALSE;
1648     while (1) {
1649 	LYmove(line, col);
1650 	if (term_options == FALSE) {
1651 	    response = LYgetch_single();
1652 	}
1653 	if (term_options || LYCharIsINTERRUPT_NO_letter(response)) {
1654 	    /*
1655 	     * Control-C or Control-G.
1656 	     */
1657 	    response = '\n';
1658 	    term_options = TRUE;
1659 	    cur_choice = orig_choice;
1660 	}
1661 #ifdef VMS
1662 	if (HadVMSInterrupt) {
1663 	    HadVMSInterrupt = FALSE;
1664 	    response = '\n';
1665 	    term_options = TRUE;
1666 	    cur_choice = orig_choice;
1667 	}
1668 #endif /* VMS */
1669 	if ((response != '\n' && response != '\r') &&
1670 	    (cmd = LKC_TO_LAC(keymap, response)) != LYK_ACTIVATE) {
1671 	    switch (cmd) {
1672 	    case LYK_HOME:
1673 		cur_choice = 0;
1674 		break;
1675 
1676 	    case LYK_END:
1677 		cur_choice = number;
1678 		break;
1679 
1680 	    case LYK_REFRESH:
1681 		lynx_force_repaint();
1682 		LYrefresh();
1683 		break;
1684 
1685 	    case LYK_QUIT:
1686 	    case LYK_ABORT:
1687 	    case LYK_PREV_DOC:
1688 		cur_choice = orig_choice;
1689 		term_options = TRUE;
1690 		break;
1691 
1692 	    case LYK_PREV_PAGE:
1693 	    case LYK_UP_HALF:
1694 	    case LYK_UP_TWO:
1695 	    case LYK_PREV_LINK:
1696 	    case LYK_LPOS_PREV_LINK:
1697 	    case LYK_FASTBACKW_LINK:
1698 	    case LYK_UP_LINK:
1699 	    case LYK_LEFT_LINK:
1700 		if (cur_choice == 0)
1701 		    cur_choice = number;	/* go back to end */
1702 		else
1703 		    cur_choice--;
1704 		break;
1705 
1706 	    case LYK_1:
1707 	    case LYK_2:
1708 	    case LYK_3:
1709 	    case LYK_4:
1710 	    case LYK_5:
1711 	    case LYK_6:
1712 	    case LYK_7:
1713 	    case LYK_8:
1714 	    case LYK_9:
1715 		if ((cmd - LYK_1 + 1) <= number) {
1716 		    cur_choice = cmd - LYK_1 + 1;
1717 		    break;
1718 		}		/* else fall through! */
1719 	    default:
1720 		if (cur_choice == number)
1721 		    cur_choice = 0;	/* go over the top and around */
1722 		else
1723 		    cur_choice++;
1724 	    }			/* end of switch */
1725 	    show_choice(choices[cur_choice], width);
1726 	    if (LYShowCursor)
1727 		LYmove(line, (col - 1));
1728 	    LYrefresh();
1729 	} else {
1730 	    /*
1731 	     * Unhighlight choice.
1732 	     */
1733 	    LYmove(line, col);
1734 	    lynx_stop_reverse();
1735 	    show_choice(choices[cur_choice], width);
1736 
1737 	    if (term_options) {
1738 		term_options = FALSE;
1739 		HTInfoMsg(CANCELLED);
1740 		HTInfoMsg("");
1741 	    } else {
1742 		_statusline(VALUE_ACCEPTED);
1743 	    }
1744 	    return cur_choice;
1745 	}
1746     }
1747 }
1748 #endif /* !NO_OPTION_MENU */
1749 
terminate_options(int sig GCC_UNUSED)1750 static void terminate_options(int sig GCC_UNUSED)
1751 {
1752     term_options = TRUE;
1753     /*
1754      * Reassert the AST.
1755      */
1756     signal(SIGINT, terminate_options);
1757 #ifdef VMS
1758     /*
1759      * Refresh the screen to get rid of the "interrupt" message.
1760      */
1761     if (!dump_output_immediately) {
1762 	lynx_force_repaint();
1763 	LYrefresh();
1764     }
1765 #endif /* VMS */
1766 }
1767 
1768 /*
1769  * Multi-Bookmark On-Line editing support.  - FMG & FM
1770  */
edit_bookmarks(void)1771 void edit_bookmarks(void)
1772 {
1773     int response = 0, def_response = 0;
1774     int MBM_current = 1;
1775 
1776 #define MULTI_OFFSET 8
1777     int a;			/* misc counter */
1778     bstring *my_data = NULL;
1779 
1780     /*
1781      * We need (MBM_V_MAXFILES + MULTI_OFFSET) lines to display the whole list
1782      * at once.  Otherwise break it up into two segments.  We know it won't be
1783      * less than that because 'o'ptions needs 23-24 at LEAST.
1784      */
1785     term_options = FALSE;
1786     signal(SIGINT, terminate_options);
1787 
1788   draw_bookmark_list:
1789     /*
1790      * Display menu of bookmarks.  NOTE that we avoid printw()'s to increase
1791      * the chances that any non-ASCII or multibyte/CJK characters will be
1792      * handled properly.  - FM
1793      */
1794 #if defined(FANCY_CURSES) || defined (USE_SLANG)
1795     if (enable_scrollback) {
1796 	LYclear();
1797     } else {
1798 	LYerase();
1799     }
1800 #else
1801     LYclear();
1802 #endif /* FANCY_CURSES || USE_SLANG */
1803     LYmove(0, 5);
1804     lynx_start_h1_color();
1805     if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) {
1806 	char *ehead_buffer = 0;
1807 
1808 	HTSprintf0(&ehead_buffer, MULTIBOOKMARKS_EHEAD_MASK, MBM_current);
1809 	LYaddstr(ehead_buffer);
1810 	FREE(ehead_buffer);
1811     } else {
1812 	LYaddstr(MULTIBOOKMARKS_EHEAD);
1813     }
1814     lynx_stop_h1_color();
1815 
1816     if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) {
1817 	for (a = ((MBM_V_MAXFILES / 2 + 1) * (MBM_current - 1));
1818 	     a <= (MBM_current * MBM_V_MAXFILES / 2); a++) {
1819 	    LYmove((3 + a) - ((MBM_V_MAXFILES / 2 + 1) * (MBM_current - 1)), 5);
1820 	    LYaddch(UCH(LYindex2MBM(a)));
1821 	    LYaddstr(" : ");
1822 	    if (MBM_A_subdescript[a])
1823 		LYaddstr(MBM_A_subdescript[a]);
1824 	    LYmove((3 + a) - ((MBM_V_MAXFILES / 2 + 1) * (MBM_current - 1)), 35);
1825 	    LYaddstr("| ");
1826 	    if (MBM_A_subbookmark[a]) {
1827 		LYaddstr(MBM_A_subbookmark[a]);
1828 	    }
1829 	}
1830     } else {
1831 	for (a = 0; a <= MBM_V_MAXFILES; a++) {
1832 	    LYmove(3 + a, 5);
1833 	    LYaddch(UCH(LYindex2MBM(a)));
1834 	    LYaddstr(" : ");
1835 	    if (MBM_A_subdescript[a])
1836 		LYaddstr(MBM_A_subdescript[a]);
1837 	    LYmove(3 + a, 35);
1838 	    LYaddstr("| ");
1839 	    if (MBM_A_subbookmark[a]) {
1840 		LYaddstr(MBM_A_subbookmark[a]);
1841 	    }
1842 	}
1843     }
1844 
1845     /*
1846      * Only needed when we have 2 screens.
1847      */
1848     if (LYlines < MBM_V_MAXFILES + MULTI_OFFSET) {
1849 	LYmove((LYlines - 4), 0);
1850 	LYaddstr("'");
1851 	lynx_start_bold();
1852 	LYaddstr("[");
1853 	lynx_stop_bold();
1854 	LYaddstr("' ");
1855 	LYaddstr(PREVIOUS);
1856 	LYaddstr(", '");
1857 	lynx_start_bold();
1858 	LYaddstr("]");
1859 	lynx_stop_bold();
1860 	LYaddstr("' ");
1861 	LYaddstr(NEXT_SCREEN);
1862     }
1863 
1864     LYmove((LYlines - 3), 0);
1865     if (!no_option_save) {
1866 	LYaddstr("'");
1867 	lynx_start_bold();
1868 	LYaddstr(">");
1869 	lynx_stop_bold();
1870 	LYaddstr("'");
1871 	LYaddstr(TO_SAVE_SEGMENT);
1872     }
1873     LYaddstr(OR_SEGMENT);
1874     LYaddstr("'");
1875     lynx_start_bold();
1876     LYaddstr("^G");
1877     lynx_stop_bold();
1878     LYaddstr("'");
1879     LYaddstr(TO_RETURN_SEGMENT);
1880 
1881     while (!term_options &&
1882 	   !LYisNonAlnumKeyname(response, LYK_PREV_DOC) &&
1883 	   !LYCharIsINTERRUPT_NO_letter(response) && response != '>') {
1884 
1885 	LYmove((LYlines - 2), 0);
1886 	lynx_start_prompt_color();
1887 	LYaddstr(MULTIBOOKMARKS_LETTER);
1888 	lynx_stop_prompt_color();
1889 
1890 	LYrefresh();
1891 	response = (def_response ? def_response : LYgetch_single());
1892 	def_response = 0;
1893 
1894 	/*
1895 	 * Check for a cancel.
1896 	 */
1897 	if (term_options || LYCharIsINTERRUPT_NO_letter(response) ||
1898 	    LYisNonAlnumKeyname(response, LYK_PREV_DOC))
1899 	    continue;
1900 
1901 	/*
1902 	 * Check for a save.
1903 	 */
1904 	if (response == '>') {
1905 	    if (!no_option_save) {
1906 		HTInfoMsg(SAVING_OPTIONS);
1907 		if (save_rc(NULL))
1908 		    HTInfoMsg(OPTIONS_SAVED);
1909 		else
1910 		    HTAlert(OPTIONS_NOT_SAVED);
1911 	    } else {
1912 		HTInfoMsg(R_TO_RETURN_TO_LYNX);
1913 		/*
1914 		 * Change response so that we don't exit the options menu.
1915 		 */
1916 		response = ' ';
1917 	    }
1918 	    continue;
1919 	}
1920 
1921 	/*
1922 	 * Check for a refresh.
1923 	 */
1924 	if (LYisNonAlnumKeyname(response, LYK_REFRESH)) {
1925 	    lynx_force_repaint();
1926 	    continue;
1927 	}
1928 
1929 	/*
1930 	 * Move between the screens - if we can't show it all at once.
1931 	 */
1932 	if ((response == ']' ||
1933 	     LYisNonAlnumKeyname(response, LYK_NEXT_PAGE)) &&
1934 	    LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) {
1935 	    MBM_current++;
1936 	    if (MBM_current >= 3)
1937 		MBM_current = 1;
1938 	    goto draw_bookmark_list;
1939 	}
1940 	if ((response == '[' ||
1941 	     LYisNonAlnumKeyname(response, LYK_PREV_PAGE)) &&
1942 	    LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) {
1943 	    MBM_current--;
1944 	    if (MBM_current <= 0)
1945 		MBM_current = 2;
1946 	    goto draw_bookmark_list;
1947 	}
1948 
1949 	/*
1950 	 * Instead of using 26 case statements, we set up a scan through the
1951 	 * letters and edit the lines that way.
1952 	 */
1953 	for (a = 0; a <= MBM_V_MAXFILES; a++) {
1954 	    if (LYMBM2index(response) == a) {
1955 		if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) {
1956 		    if (MBM_current == 1 && a > (MBM_V_MAXFILES / 2)) {
1957 			MBM_current = 2;
1958 			def_response = response;
1959 			goto draw_bookmark_list;
1960 		    }
1961 		    if (MBM_current == 2 && a < (MBM_V_MAXFILES / 2)) {
1962 			MBM_current = 1;
1963 			def_response = response;
1964 			goto draw_bookmark_list;
1965 		    }
1966 		}
1967 		_statusline(ACCEPT_DATA);
1968 
1969 		if (a > 0) {
1970 		    lynx_start_bold();
1971 		    if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET))
1972 			LYmove((3 + a)
1973 			       - ((MBM_V_MAXFILES / 2 + 1) * (MBM_current - 1)),
1974 			       9);
1975 		    else
1976 			LYmove((3 + a), 9);
1977 		    BStrCopy0(my_data,
1978 			      (!MBM_A_subdescript[a] ?
1979 			       "" : MBM_A_subdescript[a]));
1980 		    (void) LYgetBString(&my_data, FALSE, 0, NORECALL);
1981 		    lynx_stop_bold();
1982 
1983 		    if (isBEmpty(my_data)) {
1984 			FREE(MBM_A_subdescript[a]);
1985 		    } else {
1986 			StrAllocCopy(MBM_A_subdescript[a], my_data->str);
1987 		    }
1988 		    if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET))
1989 			LYmove((3 + a)
1990 			       - ((MBM_V_MAXFILES / 2 + 1)
1991 				  * (MBM_current - 1)),
1992 			       5);
1993 		    else
1994 			LYmove((3 + a), 5);
1995 		    LYaddch(UCH(LYindex2MBM(a)));
1996 		    LYaddstr(" : ");
1997 		    if (MBM_A_subdescript[a])
1998 			LYaddstr(MBM_A_subdescript[a]);
1999 		    LYclrtoeol();
2000 		    LYrefresh();
2001 		}
2002 
2003 		if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET))
2004 		    LYmove((3 + a)
2005 			   - ((MBM_V_MAXFILES / 2 + 1)
2006 			      * (MBM_current - 1)),
2007 			   35);
2008 		else
2009 		    LYmove((3 + a), 35);
2010 		LYaddstr("| ");
2011 
2012 		lynx_start_bold();
2013 		BStrCopy0(my_data, NonNull(MBM_A_subbookmark[a]));
2014 		(void) LYgetBString(&my_data, FALSE, 0, NORECALL);
2015 		lynx_stop_bold();
2016 
2017 		if (isBEmpty(my_data)) {
2018 		    if (a == 0)
2019 			StrAllocCopy(MBM_A_subbookmark[a], bookmark_page);
2020 		    else
2021 			FREE(MBM_A_subbookmark[a]);
2022 		} else {
2023 		    BStrAlloc(my_data, my_data->len + LY_MAXPATH);
2024 		    if (!LYPathOffHomeOK(my_data->str, (size_t) my_data->len)) {
2025 			LYMBM_statusline(USE_PATH_OFF_HOME);
2026 			LYSleepAlert();
2027 		    } else {
2028 			StrAllocCopy(MBM_A_subbookmark[a], my_data->str);
2029 			if (a == 0) {
2030 			    StrAllocCopy(bookmark_page, MBM_A_subbookmark[a]);
2031 			}
2032 		    }
2033 		}
2034 		if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET))
2035 		    LYmove((3 + a)
2036 			   - ((MBM_V_MAXFILES / 2 + 1)
2037 			      * (MBM_current - 1)),
2038 			   35);
2039 		else
2040 		    LYmove((3 + a), 35);
2041 		LYaddstr("| ");
2042 		if (MBM_A_subbookmark[a])
2043 		    LYaddstr(MBM_A_subbookmark[a]);
2044 		LYclrtoeol();
2045 		LYParkCursor();
2046 		break;
2047 	    }
2048 	}			/* end for */
2049     }				/* end while */
2050 
2051     BStrFree(my_data);
2052     term_options = FALSE;
2053     signal(SIGINT, cleanup_sig);
2054 }
2055 
2056 #if defined(USE_CURSES_PADS) || !defined(NO_OPTION_MENU) || (defined(USE_MOUSE) && (defined(NCURSES) || defined(PDCURSES)))
2057 
2058 /*
2059  * This function offers the choices for values of an option via a popup window
2060  * which functions like that for selection of options in a form.  - FM
2061  *
2062  * Also used for mouse popups with ncurses; this is indicated by for_mouse.
2063  */
popup_choice(int cur_choice,int line,int column,STRING2PTR choices,int i_length,int disabled,int for_mouse)2064 int popup_choice(int cur_choice,
2065 		 int line,
2066 		 int column,
2067 		 STRING2PTR choices,
2068 		 int i_length,
2069 		 int disabled,
2070 		 int for_mouse)
2071 {
2072     if (column < 0)
2073 	column = (COL_OPTION_VALUES - 1);
2074 
2075     term_options = FALSE;
2076     cur_choice = LYhandlePopupList(cur_choice,
2077 				   line,
2078 				   column,
2079 				   (STRING2PTR) choices,
2080 				   -1,
2081 				   i_length,
2082 				   disabled,
2083 				   for_mouse);
2084     switch (cur_choice) {
2085     case LYK_QUIT:
2086     case LYK_ABORT:
2087     case LYK_PREV_DOC:
2088 	term_options = TRUE;
2089 	if (!for_mouse) {
2090 	    HTUserMsg(CANCELLED);
2091 	}
2092 	break;
2093     }
2094 
2095     if (disabled || term_options) {
2096 	_statusline("");
2097     } else if (!for_mouse) {
2098 	_statusline(VALUE_ACCEPTED);
2099     }
2100     return (cur_choice);
2101 }
2102 
2103 #endif /* !NO_OPTION_MENU */
2104 #ifndef NO_OPTION_FORMS
2105 
2106 /*
2107  * I'm paranoid about mistyping strings.  Also, this way they get combined
2108  * so we don't have to worry about the intelligence of the compiler.
2109  * We don't need to burn memory like it's cheap.  We're better than that.
2110  */
2111 #define SELECTED(flag) (flag) ? selected_string : ""
2112 #define DISABLED(flag) (flag) ? disabled_string : ""
2113 
2114 typedef struct {
2115     int value;
2116     const char *LongName;
2117     const char *HtmlName;
2118 } OptValues;
2119 
2120 #define END_OPTIONS {0, 0, 0}
2121 
2122 #define HasOptValues(table) (((table) != NULL) && ((table)->LongName != NULL))
2123 
2124 typedef struct {
2125     char *tag;
2126     char *value;
2127 } PostPair;
2128 
2129 static const char selected_string[] = "selected";
2130 static const char disabled_string[] = "disabled";
2131 static const char on_string[] = N_("ON");
2132 static const char off_string[] = N_("OFF");
2133 static const char never_string[] = N_("NEVER");
2134 static const char always_string[] = N_("ALWAYS");
2135 static OptValues bool_values[] =
2136 {
2137     {FALSE, N_("OFF"), "OFF"},
2138     {TRUE, N_("ON"), "ON"},
2139     END_OPTIONS
2140 };
2141 
2142 static const char *secure_string = "secure";
2143 static char *secure_value = NULL;
2144 static const char *save_options_string = "save_options";
2145 
2146 /*
2147  * Personal Preferences
2148  */
2149 static const char *cookies_string = RC_SET_COOKIES;
2150 static const char *cookies_ignore_all_string = N_("ignore");
2151 static const char *cookies_up_to_user_string = N_("ask user");
2152 static const char *cookies_accept_all_string = N_("accept all");
2153 static const char *x_display_string = RC_DISPLAY;
2154 static const char *editor_string = RC_FILE_EDITOR;
2155 static const char *emacs_keys_string = RC_EMACS_KEYS;
2156 
2157 #if defined(ENABLE_OPTS_CHANGE_EXEC) && (defined(EXEC_LINKS) || defined(EXEC_SCRIPTS))
2158 #define EXEC_ALWAYS 2
2159 #define EXEC_LOCAL  1
2160 #define EXEC_NEVER  0
2161 static const char *exec_links_string = RC_RUN_ALL_EXECUTION_LINKS;
2162 static OptValues exec_links_values[] =
2163 {
2164     {EXEC_NEVER, N_("ALWAYS OFF"), "ALWAYS OFF"},
2165     {EXEC_LOCAL, N_("FOR LOCAL FILES ONLY"), "FOR LOCAL FILES ONLY"},
2166 #ifndef NEVER_ALLOW_REMOTE_EXEC
2167     {EXEC_ALWAYS, N_("ALWAYS ON"), "ALWAYS ON"},
2168 #endif
2169     END_OPTIONS
2170 };
2171 #endif /* ENABLE_OPTS_CHANGE_EXEC */
2172 
2173 #ifdef EXP_KEYBOARD_LAYOUT
2174 static const char *kblayout_string = RC_KBLAYOUT;
2175 #endif
2176 static const char *keypad_mode_string = RC_KEYPAD_MODE;
2177 static OptValues keypad_mode_values[] =
2178 {
2179     {NUMBERS_AS_ARROWS, N_("Numbers act as arrows"),
2180      "number_arrows"},
2181     {LINKS_ARE_NUMBERED, N_("Links are numbered"),
2182      "links_numbered"},
2183     {LINKS_AND_FIELDS_ARE_NUMBERED,
2184      N_("Links and form fields are numbered"),
2185      "links_and_forms"},
2186     {FIELDS_ARE_NUMBERED,
2187      N_("Form fields are numbered"),
2188      "forms_numbered"},
2189     END_OPTIONS
2190 };
2191 static const char *lineedit_mode_string = RC_LINEEDIT_MODE;
2192 static const char *mail_address_string = RC_PERSONAL_MAIL_ADDRESS;
2193 static const char *personal_name_string = RC_PERSONAL_MAIL_NAME;
2194 static const char *search_type_string = RC_CASE_SENSITIVE_SEARCHING;
2195 
2196 #ifndef DISABLE_FTP
2197 static const char *anonftp_password_string = RC_ANONFTP_PASSWORD;
2198 #endif
2199 
2200 static OptValues search_type_values[] =
2201 {
2202     {FALSE, N_("Case insensitive"), "case_insensitive"},
2203     {TRUE, N_("Case sensitive"), "case_sensitive"},
2204     END_OPTIONS
2205 };
2206 
2207 #if defined(USE_SLANG) || defined(COLOR_CURSES)
2208 static const char *show_color_string = RC_SHOW_COLOR;
2209 static OptValues show_color_values[] =
2210 {
2211     {SHOW_COLOR_NEVER, never_string, never_string},
2212     {SHOW_COLOR_OFF, off_string, off_string},
2213     {SHOW_COLOR_ON, on_string, on_string},
2214     {SHOW_COLOR_ALWAYS, always_string, always_string},
2215     END_OPTIONS
2216 };
2217 #endif
2218 
2219 #ifdef USE_COLOR_STYLE
2220 static const char *color_style_string = RC_COLOR_STYLE;
2221 static OptValues *color_style_values;
2222 static HTList *color_style_list;
2223 #endif
2224 
2225 #ifdef USE_DEFAULT_COLORS
2226 static const char *default_colors_string = RC_DEFAULT_COLORS;
2227 #endif
2228 
2229 static const char *show_cursor_string = RC_SHOW_CURSOR;
2230 
2231 static const char *underline_links_string = RC_UNDERLINE_LINKS;
2232 
2233 #ifdef USE_SCROLLBAR
2234 static const char *show_scrollbar_string = RC_SCROLLBAR;
2235 #endif
2236 
2237 static const char prompt_dft_string[] = N_("prompt normally");
2238 static const char prompt_yes_string[] = N_("force yes-response");
2239 static const char prompt_no_string[] = N_("force no-response");
2240 static OptValues prompt_values[] =
2241 {
2242     {FORCE_PROMPT_DFT, prompt_dft_string, prompt_dft_string},
2243     {FORCE_PROMPT_YES, prompt_yes_string, prompt_yes_string},
2244     {FORCE_PROMPT_NO, prompt_no_string, prompt_no_string},
2245     END_OPTIONS
2246 };
2247 static const char *cookie_prompt_string = RC_FORCE_COOKIE_PROMPT;
2248 
2249 static const char RFC_2109_string[] = N_("RFC 2109");
2250 static const char RFC_2965_string[] = N_("RFC 2965");
2251 static const char RFC_6265_string[] = N_("RFC 6265");
2252 static OptValues cookies_values[] =
2253 {
2254     {COOKIES_RFC_2109, RFC_2109_string, RFC_2109_string},
2255     {COOKIES_RFC_2965, RFC_2965_string, RFC_2965_string},
2256     {COOKIES_RFC_6265, RFC_6265_string, RFC_6265_string},
2257     END_OPTIONS
2258 };
2259 static const char *cookie_version_string = RC_COOKIE_VERSION;
2260 
2261 #ifdef USE_SSL
2262 static const char *ssl_prompt_string = RC_FORCE_SSL_PROMPT;
2263 #endif
2264 
2265 static const char *user_mode_string = RC_USER_MODE;
2266 static OptValues user_mode_values[] =
2267 {
2268     {NOVICE_MODE, N_("Novice"), "Novice"},
2269     {INTERMEDIATE_MODE, N_("Intermediate"), "Intermediate"},
2270     {ADVANCED_MODE, N_("Advanced"), "Advanced"},
2271     END_OPTIONS
2272 };
2273 
2274 static const char *vi_keys_string = RC_VI_KEYS;
2275 
2276 static const char *visited_links_string = RC_VISITED_LINKS;
2277 static OptValues visited_links_values[] =
2278 {
2279     {VISITED_LINKS_AS_FIRST_V, N_("By First Visit"), "first_visited"},
2280     {VISITED_LINKS_AS_FIRST_V | VISITED_LINKS_REVERSE,
2281      N_("By First Visit Reversed"), "first_visited_reversed"},
2282     {VISITED_LINKS_AS_TREE, N_("As Visit Tree"), "visit_tree"},
2283     {VISITED_LINKS_AS_LATEST, N_("By Last Visit"), "last_visited"},
2284     {VISITED_LINKS_AS_LATEST | VISITED_LINKS_REVERSE,
2285      N_("By Last Visit Reversed"), "last_visited_reversed"},
2286     END_OPTIONS
2287 };
2288 
2289 /*
2290  * Document Layout
2291  */
2292 static const char *DTD_recovery_string = RC_TAGSOUP;
2293 static OptValues DTD_type_values[] =
2294 {
2295 	/* Old_DTD variable */
2296     {TRUE, N_("relaxed (TagSoup mode)"), "tagsoup"},
2297     {FALSE, N_("strict (SortaSGML mode)"), "sortasgml"},
2298     END_OPTIONS
2299 };
2300 
2301 static const char *bad_html_string = RC_BAD_HTML;
2302 static OptValues bad_html_values[] =
2303 {
2304     {BAD_HTML_IGNORE, N_("Ignore"), "ignore"},
2305     {BAD_HTML_TRACE, N_("Add to trace-file"), "trace"},
2306     {BAD_HTML_MESSAGE, N_("Add to LYNXMESSAGES"), "message"},
2307     {BAD_HTML_WARN, N_("Warn, point to trace-file"), "warn"},
2308     END_OPTIONS
2309 };
2310 
2311 static const char *select_popups_string = RC_SELECT_POPUPS;
2312 static const char *images_string = "images";
2313 static const char *images_ignore_all_string = N_("ignore");
2314 static const char *images_use_label_string = N_("as labels");
2315 static const char *images_use_links_string = N_("as links");
2316 
2317 static const char *verbose_images_string = RC_VERBOSE_IMAGES;
2318 static OptValues verbose_images_type_values[] =
2319 {
2320 	/* verbose_img variable */
2321     {FALSE, N_("OFF"), "OFF"},
2322     {TRUE, N_("show filename"), "ON"},
2323     END_OPTIONS
2324 };
2325 
2326 static const char *collapse_br_tags_string = RC_COLLAPSE_BR_TAGS;
2327 static OptValues collapse_br_tags_values[] =
2328 {
2329 	/* LYCollapseBRs variable */
2330     {FALSE, N_("OFF"), "OFF"},
2331     {TRUE, N_("collapse"), "ON"},
2332     END_OPTIONS
2333 };
2334 
2335 static const char *trim_blank_lines_string = RC_TRIM_BLANK_LINES;
2336 static OptValues trim_blank_lines_values[] =
2337 {
2338 	/* LYtrimBlankLines variable */
2339     {FALSE, N_("OFF"), "OFF"},
2340     {TRUE, N_("trim-lines"), "ON"},
2341     END_OPTIONS
2342 };
2343 
2344 /*
2345  * Bookmark Options
2346  */
2347 static const char *mbm_string = RC_MULTI_BOOKMARK;
2348 static OptValues mbm_values[] =
2349 {
2350     {MBM_OFF, N_("OFF"), "OFF"},
2351     {MBM_STANDARD, N_("STANDARD"), "STANDARD"},
2352     {MBM_ADVANCED, N_("ADVANCED"), "ADVANCED"},
2353     END_OPTIONS
2354 };
2355 
2356 static const char *single_bookmark_string = RC_BOOKMARK_FILE;
2357 
2358 #ifdef USE_SESSIONS
2359 static const char *auto_session_string = RC_AUTO_SESSION;
2360 static const char *single_session_string = RC_SESSION_FILE;
2361 #endif
2362 
2363 /*
2364  * Character Set Options
2365  */
2366 static const char *assume_char_set_string = RC_ASSUME_CHARSET;
2367 static const char *display_char_set_string = RC_CHARACTER_SET;
2368 static const char *raw_mode_string = RC_RAW_MODE;
2369 
2370 #ifdef USE_IDN2
2371 static const char *idna_mode_string = RC_IDNA_MODE;
2372 static OptValues idna_values[] =
2373 {
2374     {LYidna2003, N_("IDNA 2003"), "idna2003"},
2375     {LYidna2008, N_("IDNA 2008"), "idna2008"},
2376     {LYidnaTR46, N_("IDNA TR46"), "idnaTR46"},
2377     {LYidnaCompat, N_("IDNA Compatible"), "idnaCompat"},
2378     END_OPTIONS
2379 };
2380 #endif
2381 
2382 #ifdef USE_LOCALE_CHARSET
2383 static const char *locale_charset_string = RC_LOCALE_CHARSET;
2384 #endif
2385 
2386 static const char *html5_charsets_string = RC_HTML5_CHARSETS;
2387 
2388 /*
2389  * File Management Options
2390  */
2391 static const char *show_dotfiles_string = RC_SHOW_DOTFILES;
2392 static const char *no_pause_string = RC_NO_PAUSE;
2393 
2394 #ifdef DIRED_SUPPORT
2395 static const char *dired_list_string = RC_DIR_LIST_STYLE;
2396 static OptValues dired_list_values[] =
2397 {
2398     {DIRS_FIRST, N_("Directories first"), "dired_dir"},
2399     {FILES_FIRST, N_("Files first"), "dired_files"},
2400     {MIXED_STYLE, N_("Mixed style"), "dired_mixed"},
2401     END_OPTIONS
2402 };
2403 
2404 #ifdef LONG_LIST
2405 static const char *dired_sort_string = RC_DIR_LIST_ORDER;
2406 static OptValues dired_sort_values[] =
2407 {
2408     {ORDER_BY_NAME, N_("By Name"), "dired_by_name"},
2409     {ORDER_BY_TYPE, N_("By Type"), "dired_by_type"},
2410     {ORDER_BY_SIZE, N_("By Size"), "dired_by_size"},
2411     {ORDER_BY_DATE, N_("By Date"), "dired_by_date"},
2412     {ORDER_BY_MODE, N_("By Mode"), "dired_by_mode"},
2413 #ifndef NO_GROUPS
2414     {ORDER_BY_USER, N_("By User"), "dired_by_user"},
2415     {ORDER_BY_GROUP, N_("By Group"), "dired_by_group"},
2416 #endif
2417     END_OPTIONS
2418 };
2419 #endif /* LONG_LIST */
2420 #endif /* DIRED_SUPPORT */
2421 
2422 #ifndef DISABLE_FTP
2423 static const char *passive_ftp_string = RC_FTP_PASSIVE;
2424 
2425 static const char *ftp_sort_string = RC_FILE_SORTING_METHOD;
2426 static OptValues ftp_sort_values[] =
2427 {
2428     {FILE_BY_NAME, N_("By Name"), "ftp_by_name"},
2429     {FILE_BY_TYPE, N_("By Type"), "ftp_by_type"},
2430     {FILE_BY_SIZE, N_("By Size"), "ftp_by_size"},
2431     {FILE_BY_DATE, N_("By Date"), "ftp_by_date"},
2432     END_OPTIONS
2433 };
2434 #endif
2435 
2436 #ifdef USE_READPROGRESS
2437 static const char *show_rate_string = RC_SHOW_KB_RATE;
2438 static OptValues rate_values[] =
2439 {
2440     {rateOFF, N_("Do not show rate"), "rate_off"},
2441     {rateBYTES, N_("Show %s/sec rate"), "rate_bytes"},
2442     {rateKB, N_("Show %s/sec rate"), "rate_kb"},
2443 #ifdef USE_READPROGRESS
2444     {rateEtaBYTES, N_("Show %s/sec, ETA"), "rate_eta_bytes"},
2445     {rateEtaKB, N_("Show %s/sec, ETA"), "rate_eta_kb"},
2446     {rateEtaBYTES2, N_("Show %s/sec (2-digits), ETA"), "rate_eta_bytes2"},
2447     {rateEtaKB2, N_("Show %s/sec (2-digits), ETA"), "rate_eta_kb2"},
2448 #endif
2449 #ifdef USE_PROGRESSBAR
2450     {rateBAR, N_("Show progressbar"), "rate_bar"},
2451 #endif
2452     END_OPTIONS
2453 };
2454 #endif /* USE_READPROGRESS */
2455 
2456 static const char *preferred_content_string = RC_PREFERRED_CONTENT_TYPE;
2457 static OptValues content_values[] =
2458 {
2459     {contentBINARY, STR_BINARY, STR_BINARY},
2460     {contentTEXT, STR_PLAINTEXT, STR_PLAINTEXT},
2461     {contentHTML, STR_HTML, STR_HTML},
2462     END_OPTIONS
2463 };
2464 
2465 /*
2466  * Presentation (MIME) types used in "Accept".
2467  */
2468 static const char *preferred_media_string = RC_PREFERRED_MEDIA_TYPES;
2469 static OptValues media_values[] =
2470 {
2471     {mediaOpt1, N_("Accept lynx's internal types"), "media_opt1"},
2472     {mediaOpt2, N_("Also accept lynx.cfg's types"), "media_opt2"},
2473     {mediaOpt3, N_("Also accept user's types"), "media_opt3"},
2474     {mediaOpt4, N_("Also accept system's types"), "media_opt4"},
2475     {mediaALL, N_("Accept all types"), "media_all"},
2476     END_OPTIONS
2477 };
2478 
2479 static const char *preferred_encoding_string = RC_PREFERRED_ENCODING;
2480 static OptValues encoding_values[] =
2481 {
2482     {encodingNONE, N_("None"), "encoding_none"},
2483 #if defined(USE_ZLIB) || defined(GZIP_PATH)
2484     {encodingGZIP, N_("gzip"), "encoding_gzip"},
2485     {encodingDEFLATE, N_("deflate"), "encoding_deflate"},
2486 #endif
2487 #if defined(USE_ZLIB) || defined(COMPRESS_PATH)
2488     {encodingCOMPRESS, N_("compress"), "encoding_compress"},
2489 #endif
2490 #if defined(USE_BZLIB) || defined(BZIP2_PATH)
2491     {encodingBZIP2, N_("bzip2"), "encoding_bzip2"},
2492 #endif
2493     {encodingALL, N_("All"), "encoding_all"},
2494     END_OPTIONS
2495 };
2496 
2497 /*
2498  * Headers transferred to remote server
2499  */
2500 static const char *http_protocol_string = RC_HTTP_PROTOCOL;
2501 static OptValues http_protocol_values[] =
2502 {
2503     {HTTP_1_0, N_("HTTP 1.0"), "HTTP_1_0"},
2504     {HTTP_1_1, N_("HTTP 1.1"), "HTTP_1_1"},
2505     END_OPTIONS
2506 };
2507 
2508 static const char *preferred_doc_char_string = RC_PREFERRED_CHARSET;
2509 static const char *preferred_doc_lang_string = RC_PREFERRED_LANGUAGE;
2510 static const char *send_user_agent_string = RC_SEND_USERAGENT;
2511 static const char *user_agent_string = RC_USERAGENT;
2512 
2513 static const char *ssl_client_certificate_file = RC_SSL_CLIENT_CERT_FILE;
2514 static const char *ssl_client_key_file = RC_SSL_CLIENT_KEY_FILE;
2515 
2516 #define PutHeader(fp, Name) \
2517 	fprintf(fp, "\n%s<em>%s</em>\n", MARGIN_STR, LYEntifyTitle(&buffer, Name));
2518 
2519 #define PutCheckBox(fp, Name, Value, disable) \
2520 	fprintf(fp,\
2521 	"<input type=\"checkbox\" name=\"%s\" %s %s>\n",\
2522 		Name, Value ? "checked" : "", disable_all?disabled_string:disable)
2523 
2524 #define PutTextInput(fp, Name, Value, Size, disable) \
2525 	fprintf(fp,\
2526 	"<input size=%d type=\"text\" name=\"%s\" value=\"%s\" %s>\n",\
2527 		(int) Size, Name, Value, disable_all?disabled_string:disable)
2528 
2529 #define PutOption(fp, flag, html, name) \
2530 	fprintf(fp,"<option value=\"%s\" %s>%s\n", html, SELECTED(flag), gettext(name))
2531 
2532 #define BeginSelect(fp, text) \
2533 	fprintf(fp,"<select name=\"%s\" %s>\n", text, disable_all?disabled_string:"")
2534 
2535 #define MaybeSelect(fp, flag, text) \
2536 	fprintf(fp,"<select name=\"%s\" %s>\n", text, disable_all?disabled_string:DISABLED(flag))
2537 
2538 #define EndSelect(fp)\
2539 	fprintf(fp,"</select>\n")
2540 
PutOptValues(FILE * fp,int value,OptValues * table)2541 static void PutOptValues(FILE *fp, int value,
2542 			 OptValues * table)
2543 {
2544     while (table->LongName != 0) {
2545 	if (table->HtmlName) {
2546 	    PutOption(fp,
2547 		      value == table->value,
2548 		      table->HtmlName,
2549 		      table->LongName);
2550 	}
2551 	table++;
2552     }
2553 }
2554 
GetOptValues(OptValues * table,char * value,int * result)2555 static BOOLEAN GetOptValues(OptValues * table, char *value,
2556 			    int *result)
2557 {
2558     while (table->LongName != 0) {
2559 	if (table->HtmlName && !strcmp(value, table->HtmlName)) {
2560 	    *result = table->value;
2561 	    return TRUE;
2562 	}
2563 	table++;
2564     }
2565     return FALSE;
2566 }
2567 
2568 #ifdef USE_COLOR_STYLE
2569 #ifdef LY_FIND_LEAKS
free_colorstyle_leaks(void)2570 void free_colorstyle_leaks(void)
2571 {
2572     FREE(color_style_values);
2573 }
2574 #endif
2575 
build_lss_enum(HTList * list)2576 void build_lss_enum(HTList *list)
2577 {
2578     int count = HTList_count(list);
2579 
2580 #ifdef LY_FIND_LEAKS
2581     atexit(free_colorstyle_leaks);
2582 #endif
2583 
2584     FREE(color_style_values);
2585     if (count != 0) {
2586 	LSS_NAMES *obj;
2587 	int position = 0;
2588 
2589 	color_style_values = typecallocn(OptValues, count + 2);
2590 
2591 	if (color_style_values == NULL)
2592 	    outofmem(__FILE__, "build_lss_enum");
2593 
2594 	color_style_values[position++] = bool_values[0];
2595 	while ((obj = HTList_objectAt(list, position - 1)) != 0) {
2596 	    color_style_values[position].value = position;
2597 	    color_style_values[position].LongName = obj->given;
2598 	    color_style_values[position].HtmlName = obj->given;
2599 	    position++;
2600 	}
2601     }
2602     color_style_list = list;
2603 }
2604 
2605 /*
2606  * Find the current lss-file in the list, to get the default value for the
2607  * form.
2608  */
get_color_style_value(void)2609 static int get_color_style_value(void)
2610 {
2611     int result = 0;
2612 
2613     if (LYuse_color_style && non_empty(lynx_lss_file)) {
2614 	LSS_NAMES *obj;
2615 	int position = 1;
2616 
2617 	while ((obj = HTList_objectAt(color_style_list, position - 1)) != 0) {
2618 	    if (obj->actual != 0 && !strcmp(obj->actual, lynx_lss_file)) {
2619 		result = position;
2620 		break;
2621 	    } else if (!strcmp(obj->given, lynx_lss_file)) {
2622 		result = position;
2623 		break;
2624 	    }
2625 	    ++position;
2626 	}
2627     }
2628     return result;
2629 }
2630 
2631 /*
2632  * Return the pathname found in the given list-item.
2633  */
get_color_style_config(int code)2634 static char *get_color_style_config(int code)
2635 {
2636     char *result = 0;
2637 
2638     if (LYuse_color_style) {
2639 	LSS_NAMES *obj;
2640 
2641 	if ((obj = HTList_objectAt(color_style_list, code - 1)) != 0) {
2642 	    result = obj->actual;
2643 	}
2644     }
2645     return result;
2646 }
2647 #endif
2648 
2649 /*
2650  * Break cgi line into array of pairs of pointers.  Don't bother trying to
2651  * be efficient.  We're not called all that often.
2652  * We come in with a string looking like:
2653  * tag1=value1&tag2=value2&...&tagN=valueN
2654  * We leave with an array of post_pairs.  The last element in the array
2655  * will have a tag pointing to NULL.
2656  * Not pretty, but works.  Hey, if strings can be null terminate arrays...
2657  */
break_data(bstring * data)2658 static PostPair *break_data(bstring *data)
2659 {
2660     char *p;
2661     PostPair *q = NULL;
2662     int count = 0;
2663 
2664     if (isBEmpty(data))
2665 	return NULL;
2666 
2667     p = BStrData(data);
2668     CTRACE((tfp, "break_data %s\n", p));
2669 
2670     q = typecalloc(PostPair);
2671     if (q == NULL)
2672 	outofmem(__FILE__, "break_data(calloc)");
2673 
2674     do {
2675 	/*
2676 	 * First, break up on '&', sliding 'p' on down the line.
2677 	 */
2678 	q[count].value = LYstrsep(&p, "&");
2679 	/*
2680 	 * Then break up on '=', sliding value down, and setting tag.
2681 	 */
2682 	q[count].tag = LYstrsep(&(q[count].value), "=");
2683 
2684 	/*
2685 	 * Clean them up a bit, in case user entered a funky string.
2686 	 */
2687 	HTUnEscape(q[count].tag);
2688 
2689 	/* In the value field we have '+' instead of ' '. So do a simple
2690 	 * find&replace on the value field before UnEscaping() - SKY
2691 	 */
2692 	{
2693 	    size_t i, len;
2694 
2695 	    len = strlen(q[count].value);
2696 	    for (i = 0; i < len; i++) {
2697 		if (q[count].value[i] == '+') {
2698 #ifdef UNIX
2699 		    /*
2700 		     * Allow for special case of options which begin with a "+" on
2701 		     * Unix - TD
2702 		     */
2703 		    if (i > 0
2704 			&& q[count].value[i + 1] == '+'
2705 			&& isalnum(UCH(q[count].value[i + 2]))) {
2706 			q[count].value[i++] = ' ';
2707 			i++;
2708 			continue;
2709 		    }
2710 #endif
2711 		    q[count].value[i] = ' ';
2712 		}
2713 	    }
2714 	}
2715 	HTUnEscape(q[count].value);
2716 	CTRACE((tfp, "...item[%d] tag=%s, value=%s\n",
2717 		count, q[count].tag, q[count].value));
2718 
2719 	count++;
2720 	/*
2721 	 * Like I said, screw efficiency.  Sides, realloc is fast on
2722 	 * Linux ;->
2723 	 */
2724 	q = typeRealloc(PostPair, q, (unsigned) (count + 1));
2725 	if (q == NULL)
2726 	    outofmem(__FILE__, "break_data(realloc)");
2727 
2728 	q[count].tag = NULL;
2729     } while (p != NULL && p[0] != '\0');
2730     return q;
2731 }
2732 
isLynxOptionsPage(const char * address,const char * portion)2733 static BOOL isLynxOptionsPage(const char *address, const char *portion)
2734 {
2735     BOOL result = FALSE;
2736 
2737     if (!strncasecomp(address, STR_LYNXOPTIONS, LEN_LYNXOPTIONS)) {
2738 	unsigned len = (unsigned) strlen(portion);
2739 
2740 	address += LEN_LYNXOPTIONS;
2741 	if (!strncasecomp(address, portion, (int) len)
2742 	    && (address[len] == '\0' || LYIsHtmlSep(address[len]))) {
2743 	    result = TRUE;
2744 	}
2745     }
2746     return result;
2747 }
2748 
2749 static int gen_options(char **newfile);
2750 
2751 /*
2752  * Handle options from the pseudo-post.  I think we really only need
2753  * post_data here, but bring along everything just in case.  It's only a
2754  * pointer.  MRC
2755  *
2756  * Options are processed in order according to gen_options(), we should not
2757  * depend on it and add boolean flags where the order is essential (save,
2758  * character sets...)
2759  *
2760  * Security:  some options are disabled in gen_options() under certain
2761  * conditions.  We *should* duplicate the same conditions here in postoptions()
2762  * to prevent user with a limited access from editing HTML options code
2763  * manually (e.g., doing 'e'dit in 'o'ptions) and submit it to access the
2764  * restricted items.  Prevent spoofing attempts from index overrun. - LP
2765  *
2766  * Exit status: NULLFILE (reload) or NORMAL (use HText cache).
2767  *
2768  * On exit, got the document which was current before the Options menu:
2769  *
2770  *   (from cache) nothing changed or no visual effect supposed:
2771  *             editor name, e-mail, etc.
2772  *
2773  *   (reload locally) to see the effect of certain changes:
2774  *             display_char_set, assume_charset, etc.
2775  *             (use 'need_reload' flag where necessary).
2776  *
2777  *   (reload from remote server and uncache on a proxy)
2778  *             few options changes should be transferred to remote server:
2779  *             preferred language, fake browser name, etc.
2780  *             (use 'need_end_reload' flag).
2781  */
2782 
postoptions(DocInfo * newdoc)2783 int postoptions(DocInfo *newdoc)
2784 {
2785     PostPair *data = 0;
2786     DocAddress WWWDoc;		/* need on exit */
2787     int i;
2788     int code = 0;
2789     BOOLEAN save_all = FALSE;
2790     int display_char_set_old = current_char_set;
2791     int old_media_value = LYAcceptMedia;
2792     BOOLEAN raw_mode_old = LYRawMode;
2793     BOOLEAN assume_char_set_changed = FALSE;
2794     BOOLEAN need_reload = FALSE;
2795     BOOLEAN need_end_reload = FALSE;
2796 
2797 #if defined(USE_SLANG) || defined(COLOR_CURSES)
2798     int CurrentShowColor = LYShowColor;
2799 #endif
2800 #ifdef USE_DEFAULT_COLORS
2801     BOOLEAN current_default_colors = LYuse_default_colors;
2802 #endif
2803 
2804     /*-------------------------------------------------
2805      * kludge a link from mbm_menu, the URL was:
2806      * "<a href=\"" LYNXOPTIONS_PAGE(MBM_MENU) "\">Goto multi-bookmark menu</a>\n"
2807      *--------------------------------------------------*/
2808 
2809     if (isLynxOptionsPage(newdoc->address, MBM_LINK)) {
2810 	FREE(newdoc->post_data);
2811 	if (no_bookmark) {
2812 	    HTAlert(BOOKMARK_CHANGE_DISALLOWED);	/* anonymous */
2813 	    return (NULLFILE);
2814 	} else if (dump_output_immediately) {
2815 	    return (NOT_FOUND);
2816 	} else {
2817 	    edit_bookmarks();
2818 	    return (NULLFILE);
2819 	}
2820     } else if (!isLynxOptionsPage(newdoc->address, "/")) {
2821 	HTAlert(RANDOM_URL_DISALLOWED);
2822 	return NULLFILE;
2823     }
2824 
2825     data = break_data(newdoc->post_data);
2826 
2827     if (!data) {
2828 	int status;
2829 
2830 	/*-------------------------------------------------
2831 	 * kludge gen_options() call:
2832 	 *--------------------------------------------------*/
2833 	status = gen_options(&newdoc->address);
2834 	if (status != NORMAL) {
2835 	    HTAlwaysAlert("Unexpected way of accessing", newdoc->address);
2836 	    FREE(newdoc->address);
2837 	    return (status);
2838 	}
2839 
2840 	/* exit to getfile() cycle */
2841 	WWWDoc.address = newdoc->address;
2842 	WWWDoc.post_data = newdoc->post_data;
2843 	WWWDoc.post_content_type = newdoc->post_content_type;
2844 	WWWDoc.bookmark = newdoc->bookmark;
2845 	WWWDoc.isHEAD = newdoc->isHEAD;
2846 	WWWDoc.safe = newdoc->safe;
2847 
2848 	if (!HTLoadAbsolute(&WWWDoc))
2849 	    return (NOT_FOUND);
2850 	LYRegisterUIPage(newdoc->address, UIP_OPTIONS_MENU);
2851 #ifdef DIRED_SUPPORT
2852 	lynx_edit_mode = FALSE;
2853 #endif /* DIRED_SUPPORT */
2854 	return (NORMAL);
2855     }
2856 
2857     if (!LYIsUIPage3(HTLoadedDocumentURL(), UIP_OPTIONS_MENU, 0) &&
2858 	!LYIsUIPage3(HTLoadedDocumentURL(), UIP_VLINKS, 0)) {
2859 	char *buf = NULL;
2860 
2861 	/*  We may have been spoofed? */
2862 	HTSprintf0(&buf,
2863 		   gettext("Use %s to invoke the Options menu!"),
2864 		   key_for_func_ext(LYK_OPTIONS, FOR_PANEL));
2865 	HTAlert(buf);
2866 	FREE(buf);
2867 	FREE(data);
2868 	return (NOT_FOUND);
2869     }
2870 
2871     /*
2872      * Checkbox will be missing from data if unchecked.
2873      */
2874     LYSendUserAgent = FALSE;
2875 
2876     for (i = 0; data[i].tag != NULL; i++) {
2877 	/*
2878 	 * This isn't really for security, but rather for avoiding that the
2879 	 * user may revisit an older instance from the history stack and submit
2880 	 * stuff which accidentally undoes changes that had been done from a
2881 	 * newer instance.  - kw
2882 	 */
2883 	if (!strcmp(data[i].tag, secure_string)) {
2884 	    if (!secure_value || strcmp(data[i].value, secure_value)) {
2885 		char *buf = NULL;
2886 
2887 		/*
2888 		 * We probably came from an older instance of the Options
2889 		 * page that had been on the history stack. - kw
2890 		 */
2891 		HTSprintf0(&buf,
2892 			   gettext("Use %s to invoke the Options menu!"),
2893 			   key_for_func_ext(LYK_OPTIONS, FOR_PANEL));
2894 		HTAlert(buf);
2895 		FREE(data);
2896 		return (NULLFILE);
2897 	    }
2898 	    FREE(secure_value);
2899 	}
2900 
2901 	/* Save options */
2902 	if (!strcmp(data[i].tag, save_options_string) && (!no_option_save)) {
2903 	    save_all = TRUE;
2904 	}
2905 
2906 	/* Cookies: SELECT */
2907 	if (!strcmp(data[i].tag, cookies_string)) {
2908 	    if (!strcmp(data[i].value, cookies_ignore_all_string)) {
2909 		LYSetCookies = FALSE;
2910 	    } else if (!strcmp(data[i].value, cookies_up_to_user_string)) {
2911 		LYSetCookies = TRUE;
2912 		LYAcceptAllCookies = FALSE;
2913 	    } else if (!strcmp(data[i].value, cookies_accept_all_string)) {
2914 		LYSetCookies = TRUE;
2915 		LYAcceptAllCookies = TRUE;
2916 	    }
2917 	}
2918 
2919 	/* X Display: INPUT */
2920 	if (!strcmp(data[i].tag, x_display_string)) {
2921 	    LYsetXDisplay(data[i].value);
2922 	    validate_x_display();
2923 	    summarize_x_display(data[i].value);
2924 	}
2925 
2926 	/* Editor: INPUT */
2927 	if (!strcmp(data[i].tag, editor_string)) {
2928 	    FREE(editor);
2929 	    StrAllocCopy(editor, data[i].value);
2930 	}
2931 
2932 	/* Emacs keys: ON/OFF */
2933 	if (!strcmp(data[i].tag, emacs_keys_string)
2934 	    && GetOptValues(bool_values, data[i].value, &code)) {
2935 	    if ((emacs_keys = (BOOLEAN) code) != FALSE) {
2936 		set_emacs_keys();
2937 	    } else {
2938 		reset_emacs_keys();
2939 	    }
2940 	}
2941 
2942 	/* Execution links: SELECT */
2943 #if defined(ENABLE_OPTS_CHANGE_EXEC) && (defined(EXEC_LINKS) || defined(EXEC_SCRIPTS))
2944 	if (!strcmp(data[i].tag, exec_links_string)
2945 	    && GetOptValues(exec_links_values, data[i].value, &code)) {
2946 #ifndef NEVER_ALLOW_REMOTE_EXEC
2947 	    local_exec = (BOOLEAN) (code == EXEC_ALWAYS);
2948 #endif /* !NEVER_ALLOW_REMOTE_EXEC */
2949 	    local_exec_on_local_files = (BOOLEAN) (code == EXEC_LOCAL);
2950 	}
2951 #endif /* ENABLE_OPTS_CHANGE_EXEC */
2952 
2953 	/* Keypad Mode: SELECT */
2954 	if (!strcmp(data[i].tag, keypad_mode_string)) {
2955 	    int newval = 0;
2956 
2957 	    if (GetOptValues(keypad_mode_values, data[i].value, &newval)
2958 		&& keypad_mode != newval) {
2959 		keypad_mode = newval;
2960 		need_reload = TRUE;
2961 		if (keypad_mode == NUMBERS_AS_ARROWS) {
2962 		    set_numbers_as_arrows();
2963 		} else {
2964 		    reset_numbers_as_arrows();
2965 		}
2966 	    }
2967 	}
2968 
2969 	/* Line edit style: SELECT */
2970 	if (!strcmp(data[i].tag, lineedit_mode_string)) {
2971 	    int newval = atoi(data[i].value);
2972 	    int j;
2973 
2974 	    /* prevent spoofing attempt */
2975 	    for (j = 0; LYEditorNames[j]; j++) {
2976 		if (j == newval)
2977 		    current_lineedit = newval;
2978 	    }
2979 	}
2980 #ifdef EXP_KEYBOARD_LAYOUT
2981 	/* Keyboard layout: SELECT */
2982 	if (!strcmp(data[i].tag, kblayout_string)) {
2983 	    int newval = atoi(data[i].value);
2984 	    int j;
2985 
2986 	    /* prevent spoofing attempt */
2987 	    for (j = 0; LYKbLayoutNames[j]; j++) {
2988 		if (j == newval)
2989 		    current_layout = newval;
2990 	    }
2991 	}
2992 #endif /* EXP_KEYBOARD_LAYOUT */
2993 
2994 	/* Mail Address: INPUT */
2995 	if (!strcmp(data[i].tag, mail_address_string)) {
2996 	    FREE(personal_mail_address);
2997 	    StrAllocCopy(personal_mail_address, data[i].value);
2998 	}
2999 #ifndef NO_ANONYMOUS_EMAIL
3000 	/* Personal Name: INPUT */
3001 	if (!strcmp(data[i].tag, personal_name_string)) {
3002 	    FREE(personal_mail_name);
3003 	    StrAllocCopy(personal_mail_name, data[i].value);
3004 	}
3005 #endif
3006 
3007 	/* Anonymous FTP Password: INPUT */
3008 #ifndef DISABLE_FTP
3009 	if (!strcmp(data[i].tag, anonftp_password_string)) {
3010 	    FREE(anonftp_password);
3011 	    StrAllocCopy(anonftp_password, data[i].value);
3012 	}
3013 #endif
3014 
3015 	/* Search Type: SELECT */
3016 	if (!strcmp(data[i].tag, search_type_string)
3017 	    && GetOptValues(search_type_values, data[i].value, &code)) {
3018 	    LYcase_sensitive = (BOOLEAN) code;
3019 	}
3020 
3021 	/* HTML error tolerance: SELECT */
3022 	if (!strcmp(data[i].tag, DTD_recovery_string)
3023 	    && GetOptValues(DTD_type_values, data[i].value, &code)) {
3024 	    if (Old_DTD != code) {
3025 		Old_DTD = code;
3026 		HTSwitchDTD(!Old_DTD);
3027 		need_reload = TRUE;
3028 	    }
3029 	}
3030 
3031 	/* Bad HTML warnings: SELECT */
3032 	if (!strcmp(data[i].tag, bad_html_string)
3033 	    && GetOptValues(bad_html_values, data[i].value, &code)) {
3034 	    cfg_bad_html = code;
3035 	}
3036 
3037 	/* Select Popups: ON/OFF */
3038 	if (!strcmp(data[i].tag, select_popups_string)
3039 	    && GetOptValues(bool_values, data[i].value, &code)) {
3040 	    LYSelectPopups = (BOOLEAN) code;
3041 	}
3042 #if defined(USE_SLANG) || defined(COLOR_CURSES)
3043 	/* Show Color: SELECT */
3044 	if (!strcmp(data[i].tag, show_color_string)
3045 	    && GetOptValues(show_color_values, data[i].value,
3046 			    &LYChosenShowColor)) {
3047 	    if (can_do_colors)
3048 		LYShowColor = LYChosenShowColor;
3049 	    if (CurrentShowColor != LYShowColor) {
3050 		lynx_force_repaint();
3051 	    }
3052 #ifdef USE_SLANG
3053 	    SLtt_Use_Ansi_Colors = (LYShowColor > SHOW_COLOR_OFF ? TRUE : FALSE);
3054 #endif
3055 	}
3056 #endif /* USE_SLANG || COLOR_CURSES */
3057 
3058 #ifdef USE_COLOR_STYLE
3059 	/* Color Style: ON/OFF */
3060 	if (!strcmp(data[i].tag, color_style_string)
3061 	    && GetOptValues(color_style_values, data[i].value, &code)) {
3062 	    if (code) {
3063 		LYuse_color_style = TRUE;
3064 		StrAllocCopy(lynx_lss_file, get_color_style_config(code));
3065 		reinit_color_styles();
3066 	    } else {
3067 		LYuse_color_style = FALSE;
3068 	    }
3069 	    update_color_style();
3070 	    lynx_force_repaint();
3071 	}
3072 #endif
3073 
3074 #ifdef USE_DEFAULT_COLORS
3075 	/* Default Colors: ON/OFF */
3076 	if (!strcmp(data[i].tag, default_colors_string)
3077 	    && GetOptValues(bool_values, data[i].value, &code)) {
3078 	    LYuse_default_colors = (BOOLEAN) code;
3079 	    if (current_default_colors != LYuse_default_colors) {
3080 		CTRACE((tfp, "default_colors changed, updating colors...\n"));
3081 		if (has_colors()) {
3082 		    if (LYuse_default_colors) {
3083 			use_default_colors();
3084 		    } else {
3085 			restart_curses();
3086 		    }
3087 		    update_default_colors();
3088 		    lynx_force_repaint();
3089 		}
3090 	    }
3091 	}
3092 #endif
3093 
3094 	/* Show Cursor: ON/OFF */
3095 	if (!strcmp(data[i].tag, show_cursor_string)
3096 	    && GetOptValues(bool_values, data[i].value, &code)) {
3097 	    LYShowCursor = (BOOLEAN) code;
3098 	}
3099 
3100 	/* Underline links: ON/OFF */
3101 	if (!strcmp(data[i].tag, underline_links_string)
3102 	    && GetOptValues(bool_values, data[i].value, &code)) {
3103 	    LYUnderlineLinks = (BOOLEAN) code;
3104 	}
3105 #ifdef USE_SCROLLBAR
3106 	/* Show Scrollbar: ON/OFF */
3107 	if (!strcmp(data[i].tag, show_scrollbar_string)
3108 	    && GetOptValues(bool_values, data[i].value, &code)) {
3109 	    LYShowScrollbar = (BOOLEAN) code;
3110 	    need_reload = TRUE;
3111 	}
3112 #endif
3113 
3114 	/* Cookie Version: SELECT */
3115 	if (!strcmp(data[i].tag, cookie_version_string))
3116 	    GetOptValues(cookies_values, data[i].value, &cookie_version);
3117 
3118 	/* Cookie Prompting: SELECT */
3119 	if (!strcmp(data[i].tag, cookie_prompt_string))
3120 	    GetOptValues(prompt_values, data[i].value, &cookie_noprompt);
3121 
3122 #ifdef USE_SSL
3123 	/* SSL Prompting: SELECT */
3124 	if (!strcmp(data[i].tag, ssl_prompt_string))
3125 	    GetOptValues(prompt_values, data[i].value, &ssl_noprompt);
3126 #endif
3127 
3128 	/* User Mode: SELECT */
3129 	if (!strcmp(data[i].tag, user_mode_string)
3130 	    && GetOptValues(user_mode_values, data[i].value, &user_mode)) {
3131 	    LYSetDisplayLines();
3132 	}
3133 
3134 	/* Type of visited pages page: SELECT */
3135 	if (!strcmp(data[i].tag, visited_links_string))
3136 	    GetOptValues(visited_links_values, data[i].value, &Visited_Links_As);
3137 
3138 	/* Show Images: SELECT */
3139 	if (!strcmp(data[i].tag, images_string)) {
3140 	    if (!strcmp(data[i].value, images_ignore_all_string)
3141 		&& !(pseudo_inline_alts == FALSE && clickable_images == FALSE)) {
3142 		pseudo_inline_alts = FALSE;
3143 		clickable_images = FALSE;
3144 		need_reload = TRUE;
3145 	    } else if (!strcmp(data[i].value, images_use_label_string)
3146 		       && !(pseudo_inline_alts == TRUE && clickable_images == FALSE)) {
3147 		pseudo_inline_alts = TRUE;
3148 		clickable_images = FALSE;
3149 		need_reload = TRUE;
3150 	    } else if (!strcmp(data[i].value, images_use_links_string)
3151 		       && !(clickable_images == TRUE)) {
3152 		clickable_images = TRUE;
3153 		need_reload = TRUE;
3154 	    }
3155 	}
3156 
3157 	/* Verbose Images: ON/OFF */
3158 	if (!strcmp(data[i].tag, verbose_images_string)
3159 	    && GetOptValues(verbose_images_type_values, data[i].value, &code)) {
3160 	    if (verbose_img != code) {
3161 		verbose_img = (BOOLEAN) code;
3162 		need_reload = TRUE;
3163 	    }
3164 	}
3165 
3166 	/* Collapse BR Tags: ON/OFF */
3167 	if (!strcmp(data[i].tag, collapse_br_tags_string)
3168 	    && GetOptValues(collapse_br_tags_values, data[i].value, &code)) {
3169 	    if (LYCollapseBRs != code) {
3170 		LYCollapseBRs = (BOOLEAN) code;
3171 		need_reload = TRUE;
3172 	    }
3173 	}
3174 
3175 	/* Trim Blank Lines: ON/OFF */
3176 	if (!strcmp(data[i].tag, trim_blank_lines_string)
3177 	    && GetOptValues(trim_blank_lines_values, data[i].value, &code)) {
3178 	    if (LYtrimBlankLines != code) {
3179 		LYtrimBlankLines = (BOOLEAN) code;
3180 		need_reload = TRUE;
3181 	    }
3182 	}
3183 
3184 	/* VI Keys: ON/OFF */
3185 	if (!strcmp(data[i].tag, vi_keys_string)
3186 	    && GetOptValues(bool_values, data[i].value, &code)) {
3187 	    if ((vi_keys = (BOOLEAN) code) != FALSE) {
3188 		set_vi_keys();
3189 	    } else {
3190 		reset_vi_keys();
3191 	    }
3192 	}
3193 
3194 	/* Bookmarks File Menu: SELECT */
3195 	if (!strcmp(data[i].tag, mbm_string) && (!LYMBMBlocked)) {
3196 	    GetOptValues(mbm_values, data[i].value, &LYMultiBookmarks);
3197 	}
3198 
3199 	/* Default Bookmarks filename: INPUT */
3200 	if (!strcmp(data[i].tag, single_bookmark_string) && (!no_bookmark)) {
3201 	    if (strcmp(data[i].value, "")) {
3202 		FREE(bookmark_page);
3203 		StrAllocCopy(bookmark_page, data[i].value);
3204 	    }
3205 	}
3206 #ifdef USE_SESSIONS
3207 	/* Auto Session: ON/OFF */
3208 	if (!strcmp(data[i].tag, auto_session_string)
3209 	    && GetOptValues(bool_values, data[i].value, &code)) {
3210 	    LYAutoSession = (BOOLEAN) code;
3211 	}
3212 
3213 	/* Default Session filename: INPUT */
3214 	if (!strcmp(data[i].tag, single_session_string)) {
3215 	    if (strcmp(data[i].value, "")) {
3216 		FREE(LYSessionFile);
3217 		StrAllocCopy(LYSessionFile, data[i].value);
3218 	    }
3219 	}
3220 #endif
3221 
3222 	/* Assume Character Set: SELECT */
3223 	if (!strcmp(data[i].tag, assume_char_set_string)) {
3224 	    int newval = UCGetLYhndl_byMIME(data[i].value);
3225 
3226 	    if (newval >= 0
3227 		&& ((raw_mode_old &&
3228 		     newval != safeUCGetLYhndl_byMIME(UCAssume_MIMEcharset))
3229 		    || (!raw_mode_old &&
3230 			newval != UCLYhndl_for_unspec)
3231 		)) {
3232 
3233 		UCLYhndl_for_unspec = newval;
3234 		StrAllocCopy(UCAssume_MIMEcharset, data[i].value);
3235 		assume_char_set_changed = TRUE;
3236 	    }
3237 	}
3238 #ifdef USE_LOCALE_CHARSET
3239 	/* Use locale-based character set: ON/OFF */
3240 	if (!strcmp(data[i].tag, locale_charset_string)
3241 	    && GetOptValues(bool_values, data[i].value, &code)) {
3242 	    LYLocaleCharset = (BOOLEAN) code;
3243 	}
3244 #endif
3245 	/* Use HTML5 charset replacements: ON/OFF */
3246 	if (!strcmp(data[i].tag, html5_charsets_string)
3247 	    && GetOptValues(bool_values, data[i].value, &code)) {
3248 	    html5_charsets = (BOOLEAN) code;
3249 	    assume_char_set_changed = TRUE;
3250 	}
3251 
3252 	/* Display Character Set: SELECT */
3253 	if (!strcmp(data[i].tag, display_char_set_string)) {
3254 	    int newval = atoi(data[i].value);
3255 	    int j;
3256 
3257 	    /* prevent spoofing attempt */
3258 	    for (j = 0; LYchar_set_names[j]; j++) {
3259 		if (j == newval)
3260 		    current_char_set = newval;
3261 	    }
3262 	}
3263 #ifdef USE_IDN2
3264 	/* Internationalized Domain Names: SELECT */
3265 	if (!strcmp(data[i].tag, idna_mode_string)
3266 	    && GetOptValues(idna_values, data[i].value, &code)) {
3267 	    LYidnaMode = code;
3268 	}
3269 #endif
3270 
3271 	/* Raw Mode: ON/OFF */
3272 	if (!strcmp(data[i].tag, raw_mode_string)
3273 	    && GetOptValues(bool_values, data[i].value, &code)) {
3274 	    LYRawMode = (BOOLEAN) code;
3275 	}
3276 #ifndef DISABLE_FTP
3277 	/*
3278 	 * passive ftp: ON/OFF
3279 	 */
3280 	if (!strcmp(data[i].tag, passive_ftp_string)) {
3281 	    ftp_passive = (BOOLEAN) code;
3282 	}
3283 
3284 	/*
3285 	 * ftp sort: SELECT
3286 	 */
3287 	if (!strcmp(data[i].tag, ftp_sort_string)) {
3288 	    GetOptValues(ftp_sort_values, data[i].value, &HTfileSortMethod);
3289 	}
3290 #endif /* DISABLE_FTP */
3291 
3292 #ifdef DIRED_SUPPORT
3293 	/* Local Directory Style: SELECT */
3294 	if (!strcmp(data[i].tag, dired_list_string)) {
3295 	    GetOptValues(dired_list_values, data[i].value, &dir_list_style);
3296 	}
3297 #ifdef LONG_LIST
3298 	/* Local Directory Order: SELECT */
3299 	if (!strcmp(data[i].tag, dired_sort_string)) {
3300 	    GetOptValues(dired_sort_values, data[i].value, &dir_list_order);
3301 	}
3302 #endif /* LONG_LIST */
3303 #endif /* DIRED_SUPPORT */
3304 
3305 	/* Show dot files: ON/OFF */
3306 	if (!strcmp(data[i].tag, show_dotfiles_string) && (!no_dotfiles)
3307 	    && GetOptValues(bool_values, data[i].value, &code)) {
3308 	    show_dotfiles = (BOOLEAN) code;
3309 	}
3310 
3311 	/* Pause when showing messages: ON/OFF */
3312 	if (!strcmp(data[i].tag, no_pause_string)
3313 	    && GetOptValues(bool_values, data[i].value, &code)) {
3314 	    no_pause = (BOOLEAN) !code;
3315 	}
3316 #ifdef USE_READPROGRESS
3317 	/* Show Transfer Rate: enumerated value */
3318 	if (!strcmp(data[i].tag, show_rate_string)
3319 	    && GetOptValues(rate_values, data[i].value, &code)) {
3320 	    LYTransferRate = code;
3321 	}
3322 #endif /* USE_READPROGRESS */
3323 
3324 	/* Preferred Content Type: SELECT */
3325 	if (!strcmp(data[i].tag, preferred_content_string)) {
3326 	    GetOptValues(content_values, data[i].value, &LYContentType);
3327 	}
3328 
3329 	/* Preferred Media Type: SELECT */
3330 	if (!strcmp(data[i].tag, preferred_media_string)) {
3331 	    GetOptValues(media_values, data[i].value, &LYAcceptMedia);
3332 	}
3333 
3334 	/* Preferred Encoding: SELECT */
3335 	if (!strcmp(data[i].tag, preferred_encoding_string)) {
3336 	    GetOptValues(encoding_values, data[i].value, &LYAcceptEncoding);
3337 	}
3338 
3339 	/* Preferred Document Character Set: INPUT */
3340 	if (!strcmp(data[i].tag, preferred_doc_char_string)) {
3341 	    if (strcmp(pref_charset, data[i].value)) {
3342 		FREE(pref_charset);
3343 		StrAllocCopy(pref_charset, data[i].value);
3344 		need_end_reload = TRUE;
3345 	    }
3346 	}
3347 
3348 	/* Preferred Document Language: INPUT */
3349 	if (!strcmp(data[i].tag, preferred_doc_lang_string)) {
3350 	    if (strcmp(language, data[i].value)) {
3351 		FREE(language);
3352 		StrAllocCopy(language, data[i].value);
3353 		need_end_reload = TRUE;
3354 	    }
3355 	}
3356 
3357 	/*
3358 	 * HTTP protocol: SELECT
3359 	 */
3360 	if (!strcmp(data[i].tag, http_protocol_string)) {
3361 	    GetOptValues(http_protocol_values, data[i].value, &HTprotocolLevel);
3362 	}
3363 
3364 	/* Send User Agent: INPUT */
3365 	if (!strcmp(data[i].tag, send_user_agent_string)) {
3366 	    LYSendUserAgent = (BOOLEAN) !strcasecomp(data[i].value, "ON");
3367 	}
3368 
3369 	if (!strcmp(data[i].tag, ssl_client_certificate_file)) {
3370 	    FREE(SSL_client_cert_file);
3371 	    StrAllocCopy(SSL_client_cert_file, data[i].value);
3372 	}
3373 
3374 	if (!strcmp(data[i].tag, ssl_client_key_file)) {
3375 	    FREE(SSL_client_key_file);
3376 	    StrAllocCopy(SSL_client_key_file, data[i].value);
3377 	}
3378 
3379 	/* User Agent: INPUT */
3380 	if (!strcmp(data[i].tag, user_agent_string) && (!no_useragent)) {
3381 	    if (strcmp(LYUserAgent, data[i].value)) {
3382 		need_end_reload = TRUE;
3383 		FREE(LYUserAgent);
3384 		/* ignore Copyright warning ? */
3385 		StrAllocCopy(LYUserAgent,
3386 			     *(data[i].value)
3387 			     ? data[i].value
3388 			     : LYUserAgentDefault);
3389 		if (!LYCheckUserAgent()) {
3390 		    HTAlert(UA_PLEASE_USE_LYNX);
3391 		}
3392 	    }
3393 	}
3394     }				/* end of loop */
3395 
3396     /*
3397      * Process the flags:
3398      */
3399 #ifdef USE_LOCALE_CHARSET
3400     LYFindLocaleCharset();
3401 #endif
3402 
3403     if (old_media_value != LYAcceptMedia)
3404 	HTFilterPresentations();
3405 
3406     if (display_char_set_old != current_char_set ||
3407 	raw_mode_old != LYRawMode ||
3408 	assume_char_set_changed) {
3409 	/*
3410 	 * charset settings: the order is essential here.
3411 	 */
3412 	if (display_char_set_old != current_char_set) {
3413 	    /*
3414 	     * Set the LYUseDefaultRawMode value and character handling if
3415 	     * LYRawMode was changed.  - FM
3416 	     */
3417 	    LYUseDefaultRawMode = TRUE;
3418 	    HTMLUseCharacterSet(current_char_set);
3419 #ifdef CAN_SWITCH_DISPLAY_CHARSET
3420 	    /* Deduce whether the user wants autoswitch: */
3421 	    switch_display_charsets =
3422 		(current_char_set == auto_display_charset
3423 		 || current_char_set == auto_other_display_charset);
3424 #endif
3425 	}
3426 	if (assume_char_set_changed && HTCJK != JAPANESE) {
3427 	    LYRawMode = (BOOLEAN) (UCLYhndl_for_unspec == current_char_set);
3428 	}
3429 	if (raw_mode_old != LYRawMode || assume_char_set_changed) {
3430 	    /*
3431 	     * Set the raw 8-bit or CJK mode defaults and character set if
3432 	     * changed.  - FM
3433 	     */
3434 	    HTMLSetUseDefaultRawMode(current_char_set, LYRawMode);
3435 	    HTMLSetCharacterHandling(current_char_set);
3436 	}
3437 	need_reload = TRUE;
3438     }
3439     /* end of charset settings */
3440 
3441     BStrFree(newdoc->post_data);
3442     FREE(data);
3443     if (save_all) {
3444 	HTInfoMsg(SAVING_OPTIONS);
3445 	LYrcShowColor = LYChosenShowColor;
3446 	if (save_rc(NULL)) {
3447 	    HTInfoMsg(OPTIONS_SAVED);
3448 	} else {
3449 	    HTAlert(OPTIONS_NOT_SAVED);
3450 	}
3451     }
3452 
3453     /*
3454      * Exit:  working around the previous document.  Being out of
3455      * mainloop()/getfile() cycle, do things manually.
3456      */
3457     CTRACE((tfp, "\nLYOptions.c/postoptions(): exiting...\n"));
3458     CTRACE((tfp, "                            need_reload = %s\n",
3459 	    need_reload ? "TRUE" : "FALSE"));
3460     CTRACE((tfp, "                            need_end_reload = %s\n",
3461 	    need_end_reload ? "TRUE" : "FALSE"));
3462 
3463     /*  Options menu was pushed before postoptions(), so pop-up. */
3464     LYpop(newdoc);
3465     WWWDoc.address = newdoc->address;
3466     WWWDoc.post_data = newdoc->post_data;
3467     WWWDoc.post_content_type = newdoc->post_content_type;
3468     WWWDoc.bookmark = newdoc->bookmark;
3469     WWWDoc.isHEAD = newdoc->isHEAD;
3470     WWWDoc.safe = newdoc->safe;
3471     LYforce_no_cache = FALSE;	/* ! */
3472     LYoverride_no_cache = TRUE;	/* ! */
3473     /*
3474      * Working out of getfile() cycle we reset *no_cache manually here so
3475      * HTLoadAbsolute() will return "Document already in memory":  it was
3476      * forced reloading Options Menu again without this (overhead).
3477      *
3478      * Probably *no_cache was set in a wrong position because of
3479      * the internal page...
3480      */
3481     if (!HTLoadAbsolute(&WWWDoc))
3482 	return (NOT_FOUND);
3483 
3484     HTuncache_current_document();	/* will never use again */
3485 
3486     /*
3487      * Return to previous doc, not to options menu!  Reload the document we had
3488      * before the options menu but uncache only when necessary (Hurrah, user!):
3489      */
3490     LYpop(newdoc);
3491     WWWDoc.address = newdoc->address;
3492     WWWDoc.post_data = newdoc->post_data;
3493     WWWDoc.post_content_type = newdoc->post_content_type;
3494     WWWDoc.bookmark = newdoc->bookmark;
3495     WWWDoc.isHEAD = newdoc->isHEAD;
3496     WWWDoc.safe = newdoc->safe;
3497     LYforce_no_cache = FALSE;	/* see below */
3498     LYoverride_no_cache = TRUE;	/* see below */
3499     /*
3500      * Re-setting of *no_cache is probably not required here but this is a
3501      * guarantee against _double_ reloading over the net in case prev document
3502      * has its own "no cache" attribute and options menu set "need_reload"
3503      * also.  Force this HTLoadAbsolute() to return "Document already in
3504      * memory".
3505      */
3506     if (!HTLoadAbsolute(&WWWDoc))
3507 	return (NOT_FOUND);
3508 
3509     /*
3510      * Now most interesting part: reload document when necessary.
3511      * **********************************************************
3512      */
3513 
3514     reloading = FALSE;		/* set manually */
3515     /* force end-to-end reload from remote server if change LYUserAgent or
3516      * language or pref_charset (marked by need_end_reload flag above), from
3517      * old-style LYK_OPTIONS (mainloop):
3518      */
3519     if ((need_end_reload == TRUE &&
3520 	 (StrNCmp(newdoc->address, "http", 4) == 0 ||
3521 	  isLYNXCGI(newdoc->address)))) {
3522 	/*
3523 	 * An option has changed which may influence content negotiation, and
3524 	 * the resource is from a http or https or lynxcgi URL (the only
3525 	 * protocols which currently do anything with this information).  Set
3526 	 * reloading = TRUE so that proxy caches will be flushed, which is
3527 	 * necessary until the time when all proxies understand HTTP 1.1 Vary:
3528 	 * and all Servers properly use it...  Treat like case LYK_RELOAD (see
3529 	 * comments there).  - KW
3530 	 */
3531 	reloading = TRUE;	/* global flag */
3532 	need_reload = TRUE;	/* this was probably already TRUE, don't worry */
3533     }
3534 
3535     if (need_reload == FALSE) {
3536 	/*  no uncache, already loaded */
3537 	CTRACE((tfp, "LYOptions.c/postoptions(): now really exit.\n\n"));
3538 	return (NORMAL);
3539     } else {
3540 	/*  update HText cache */
3541 
3542 	/*
3543 	 * see LYK_RELOAD & LYK_OPTIONS in mainloop for details...
3544 	 */
3545 	if (HTisDocumentSource()) {
3546 	    srcmode_for_next_retrieval(1);
3547 	}
3548 #ifdef USE_SOURCE_CACHE
3549 	if (reloading == FALSE) {
3550 	    /* one more attempt to be smart enough: */
3551 	    if (HTcan_reparse_document()) {
3552 		if (!HTreparse_document())
3553 		    srcmode_for_next_retrieval(0);
3554 		CTRACE((tfp, "LYOptions.c/postoptions(): now really exit.\n\n"));
3555 		return (NORMAL);
3556 	    }
3557 	}
3558 #endif
3559 	if (newdoc->post_data != NULL && !newdoc->safe &&
3560 	    confirm_post_resub(newdoc->address, newdoc->title, 2, 1) == FALSE) {
3561 	    HTInfoMsg(WILL_NOT_RELOAD_DOC);
3562 	    if (HTisDocumentSource()) {
3563 		srcmode_for_next_retrieval(0);
3564 	    }
3565 	    return (NORMAL);
3566 	}
3567 
3568 	HEAD_request = HTLoadedDocumentIsHEAD();
3569 	/*  uncache and load again */
3570 	HTuncache_current_document();
3571 	LYpush(newdoc, FALSE);
3572 	CTRACE((tfp, "LYOptions.c/postoptions(): now really exit.\n\n"));
3573 	return (NULLFILE);
3574     }
3575 
3576     /******** Done! **************************************************/
3577 }
3578 
NewSecureValue(void)3579 static char *NewSecureValue(void)
3580 {
3581     static char oops[] = "?";
3582 
3583     FREE(secure_value);
3584     if ((secure_value = typeMallocn(char, 80)) != 0) {
3585 #if defined(RAND_MAX)
3586 	long key = (long) lynx_rand();
3587 
3588 #else
3589 	long key = (long) secure_value + (long) time(0);
3590 #endif
3591 	sprintf(secure_value, "%ld", key);
3592 	return secure_value;
3593     }
3594     return oops;
3595 }
3596 
3597 #define LABEL_LEN 33
3598 
3599 /*
3600  * Note: the 'value' we are passing here is a local copy of the "same" string
3601  * as is used in LYrcFile.c to index the saveable options.
3602  */
PutLabel(FILE * fp,const char * name,const char * value)3603 static void PutLabel(FILE *fp, const char *name,
3604 		     const char *value)
3605 {
3606     int have = (int) strlen(name);
3607     int want = LABEL_LEN;
3608     int need = LYstrExtent(name, have, want);
3609     char *buffer = NULL;
3610 
3611     fprintf(fp, "%s%s", MARGIN_STR, LYEntifyTitle(&buffer, NonNull(name)));
3612 
3613     if (will_save_rc(value) && !no_option_save) {
3614 	while (need++ < want)
3615 	    fprintf(fp, "&nbsp;");
3616     } else {
3617 	want -= 3;
3618 	if (need < want) {
3619 	    fprintf(fp, "&nbsp;");
3620 	    ++need;
3621 	}
3622 	fprintf(fp, "(!)");
3623 	while (need++ < want) {
3624 	    fprintf(fp, "&nbsp;");
3625 	}
3626     }
3627     fprintf(fp, ": ");
3628     FREE(buffer);
3629 }
3630 
3631 /*
3632  * For given a list of the .lynxrc names for boolean flags that make up a
3633  * composite setting, check if any are not writable for the .lynxrc file.  If
3634  * so, return that name, so the subsequence will_save_rc() check in PutLabel()
3635  * will flag the composite as not-saved.
3636  */
check_if_write_lynxrc(STRING2PTR table)3637 static const char *check_if_write_lynxrc(STRING2PTR table)
3638 {
3639     int n;
3640     const char *result = NULL;
3641 
3642     for (n = 0; table[n] != 0; ++n) {
3643 	result = table[n];
3644 	if (!will_save_rc(result))
3645 	    break;
3646     }
3647     return result;
3648 }
3649 
3650 /*
3651  * The options menu treats "Cookies" as a single enumeration, but it is read
3652  * from lynx.cfg (and perhaps .lynxrc) as a set of booleans.  Check if any are
3653  * not writable to .lynxrc, so we can show the user.
3654  */
will_save_cookies(void)3655 static const char *will_save_cookies(void)
3656 {
3657     static const char *table[] =
3658     {
3659 	RC_SET_COOKIES,		/* LYSetCookies */
3660 	RC_ACCEPT_ALL_COOKIES,	/* LYAcceptAllCookies */
3661 	NULL
3662     };
3663 
3664     return check_if_write_lynxrc(table);
3665 }
3666 
3667 /*
3668  * The options menu treats "Show images" as a single enumeration, but it is
3669  * read from lynx.cfg (and perhaps .lynxrc) as a set of booleans.  Check if any
3670  * are not writable to .lynxrc, so we can show the user.
3671  */
will_save_images(void)3672 static const char *will_save_images(void)
3673 {
3674     static const char *table[] =
3675     {
3676 	RC_MAKE_PSEUDO_ALTS_FOR_INLINES,	/* pseudo_inline_alts */
3677 	RC_MAKE_LINKS_FOR_ALL_IMAGES,	/* clickable_images */
3678 	NULL
3679     };
3680 
3681     return check_if_write_lynxrc(table);
3682 }
3683 
3684 /*
3685  * The visited-links menu is used from the visited-links page as well as the
3686  * options page.
3687  */
LYMenuVisitedLinks(FILE * fp0,int disable_all)3688 void LYMenuVisitedLinks(FILE *fp0, int disable_all)
3689 {
3690     BeginSelect(fp0, visited_links_string);
3691     PutOptValues(fp0, Visited_Links_As, visited_links_values);
3692     EndSelect(fp0);
3693 }
3694 
3695 /*
3696  * Okay, someone wants to change options.  So, let's gen up a form for them
3697  * and pass it around.  Gor, this is ugly.  Be a lot easier in Bourne with
3698  * "here" documents.  :->
3699  * Basic Strategy:  For each option, throw up the appropriate type of
3700  * control, giving defaults as appropriate.  If nothing else, we're
3701  * probably going to test every control there is.  MRC
3702  *
3703  * This function is synchronized with postoptions().  Read the comments in
3704  * postoptions() header if you change something in gen_options().
3705  */
gen_options(char ** newfile)3706 static int gen_options(char **newfile)
3707 {
3708     static char tempfile[LY_MAXPATH] = "\0";
3709 
3710     int i;
3711     char *buffer = NULL;
3712     BOOLEAN disable_all = FALSE;
3713     FILE *fp0;
3714     size_t cset_len = 0;
3715     size_t text_len = (size_t) ((LYcolLimit > 45)
3716 				? LYcolLimit - (LABEL_LEN + 2 + MARGIN_LEN)
3717 				: 7);	/* cf: PutLabel */
3718 
3719     if ((fp0 = InternalPageFP(tempfile, TRUE)) == 0)
3720 	return (NOT_FOUND);
3721 
3722     LYLocalFileToURL(newfile, tempfile);
3723 
3724     /* This should not be needed if we regenerate the temp file every time with
3725      * a new name, which just happened above in the case
3726      * LYReuseTempfiles==FALSE.  Even for LYReuseTempfiles=TRUE, code at the
3727      * end of postoptions() may remove an older cached version from memory if
3728      * that version of the page was left by submitting changes.  - kw
3729      * 1999-11-27
3730      * If access to the actual file via getfile() later fails (maybe because of
3731      * some restrictions), mainloop may leave this flag on after popping the
3732      * previous doc which is then unnecessarily reloaded.  But I changed
3733      * mainloop to reset the flag.  - kw 1999-05-24
3734      */
3735     LYforce_no_cache = TRUE;
3736 
3737     /*
3738      * Without LYUseFormsOptions set we should maybe not even get here.
3739      * However, it's possible we do; disable the form in that case. - kw
3740      */
3741 #ifndef NO_OPTION_MENU
3742     if (!LYUseFormsOptions)
3743 	disable_all = TRUE;
3744 #endif
3745 
3746     BeginInternalPage(fp0, OPTIONS_TITLE, NULL);	/* help link below */
3747 
3748     /*
3749      * I do C, not HTML.  Feel free to pretty this up.
3750      */
3751     fprintf(fp0, "<form action=\"%s\" method=\"post\">\n", STR_LYNXOPTIONS);
3752     /*
3753      * use following with some sort of one shot secret key akin to NCSA
3754      * (or was it CUTE?) telnet one shot password to allow ftp to self.
3755      * to prevent spoofing.
3756      */
3757     fprintf(fp0, "<input name=\"%s\" type=\"hidden\" value=\"%s\">\n",
3758 	    secure_string, NewSecureValue());
3759 
3760     /*
3761      * visible text begins here
3762      */
3763 
3764     /* Submit/Reset/Help */
3765     fprintf(fp0, "<p align=center>\n");
3766     if (!disable_all) {
3767 	fprintf(fp0,
3768 		"<input type=\"submit\" value=\"%s\"> - \n",
3769 		LYEntifyValue(&buffer, ACCEPT_CHANGES));
3770 	fprintf(fp0,
3771 		"<input type=\"reset\" value=\"%s\"> - \n",
3772 		LYEntifyValue(&buffer, RESET_CHANGES));
3773 	fprintf(fp0,
3774 		"%s - \n",
3775 		LYEntifyTitle(&buffer, CANCEL_CHANGES));
3776     }
3777     fprintf(fp0, "<a href=\"%s%s\">%s</a>\n",
3778 	    helpfilepath, LYEntifyTitle(&buffer, OPTIONS_HELP), TO_HELP);
3779 
3780     /* Save options */
3781     if (!no_option_save) {
3782 	if (!disable_all) {
3783 	    fprintf(fp0, "<p align=center>%s: ", LYEntifyTitle(&buffer, SAVE_OPTIONS));
3784 	    fprintf(fp0, "<input type=\"checkbox\" name=\"%s\">\n",
3785 		    save_options_string);
3786 	}
3787 	fprintf(fp0, "<br>%s\n",
3788 		LYEntifyTitle(&buffer,
3789 			      gettext("(options marked with (!) will not be saved)")));
3790     }
3791 
3792     /*
3793      * preformatted text follows
3794      */
3795     fprintf(fp0, "<pre>\n");
3796 
3797     PutHeader(fp0, gettext("General Preferences"));
3798     /*****************************************************************/
3799 
3800     /* User Mode: SELECT */
3801     PutLabel(fp0, gettext("User mode"), user_mode_string);
3802     BeginSelect(fp0, user_mode_string);
3803     PutOptValues(fp0, user_mode, user_mode_values);
3804     EndSelect(fp0);
3805 
3806     /* Editor: INPUT */
3807     PutLabel(fp0, gettext("Editor"), editor_string);
3808     PutTextInput(fp0, editor_string, NonNull(editor), text_len,
3809 		 DISABLED(no_editor || system_editor));
3810 
3811     /* Search Type: SELECT */
3812     PutLabel(fp0, gettext("Type of Search"), search_type_string);
3813     BeginSelect(fp0, search_type_string);
3814     PutOptValues(fp0, LYcase_sensitive, search_type_values);
3815     EndSelect(fp0);
3816 
3817     PutHeader(fp0, gettext("Security and Privacy"));
3818     /*****************************************************************/
3819 
3820     /* Cookies: SELECT */
3821     PutLabel(fp0, gettext("Cookies"), will_save_cookies());
3822     BeginSelect(fp0, cookies_string);
3823     PutOption(fp0, !LYSetCookies,
3824 	      cookies_ignore_all_string,
3825 	      cookies_ignore_all_string);
3826     PutOption(fp0, LYSetCookies && !LYAcceptAllCookies,
3827 	      cookies_up_to_user_string,
3828 	      cookies_up_to_user_string);
3829     PutOption(fp0, LYSetCookies && LYAcceptAllCookies,
3830 	      cookies_accept_all_string,
3831 	      cookies_accept_all_string);
3832     EndSelect(fp0);
3833 
3834     /* Cookie Version: SELECT */
3835     PutLabel(fp0, gettext("Cookie RFC-version"), cookie_version_string);
3836     BeginSelect(fp0, cookie_version_string);
3837     PutOptValues(fp0, cookie_version, cookies_values);
3838     EndSelect(fp0);
3839 
3840     /* Cookie Prompting: SELECT */
3841     PutLabel(fp0, gettext("Invalid-Cookie Prompting"), cookie_prompt_string);
3842     BeginSelect(fp0, cookie_prompt_string);
3843     PutOptValues(fp0, cookie_noprompt, prompt_values);
3844     EndSelect(fp0);
3845 
3846 #ifdef USE_SSL
3847     /* SSL Prompting: SELECT */
3848     PutLabel(fp0, gettext("SSL Prompting"), ssl_prompt_string);
3849     BeginSelect(fp0, ssl_prompt_string);
3850     PutOptValues(fp0, ssl_noprompt, prompt_values);
3851     EndSelect(fp0);
3852 
3853     PutLabel(fp0, gettext("SSL client certificate file"), ssl_client_certificate_file);
3854     PutTextInput(fp0, ssl_client_certificate_file,
3855 		 NonNull(SSL_client_cert_file), text_len, "");
3856 
3857     PutLabel(fp0, gettext("SSL client key file"), ssl_client_key_file);
3858     PutTextInput(fp0, ssl_client_key_file,
3859 		 NonNull(SSL_client_key_file), text_len, "");
3860 
3861 #endif
3862 
3863     PutHeader(fp0, gettext("Keyboard Input"));
3864     /*****************************************************************/
3865 
3866     /* Keypad Mode: SELECT */
3867     PutLabel(fp0, gettext("Keypad mode"), keypad_mode_string);
3868     BeginSelect(fp0, keypad_mode_string);
3869     PutOptValues(fp0, keypad_mode, keypad_mode_values);
3870     EndSelect(fp0);
3871 
3872     /* Emacs keys: ON/OFF */
3873     PutLabel(fp0, gettext("Emacs keys"), emacs_keys_string);
3874     BeginSelect(fp0, emacs_keys_string);
3875     PutOptValues(fp0, emacs_keys, bool_values);
3876     EndSelect(fp0);
3877 
3878     /* VI Keys: ON/OFF */
3879     PutLabel(fp0, gettext("VI keys"), vi_keys_string);
3880     BeginSelect(fp0, vi_keys_string);
3881     PutOptValues(fp0, vi_keys, bool_values);
3882     EndSelect(fp0);
3883 
3884     /* Line edit style: SELECT */
3885     if (LYEditorNames[1]) {	/* well, at least 2 line edit styles available */
3886 	PutLabel(fp0, gettext("Line edit style"), lineedit_mode_string);
3887 	BeginSelect(fp0, lineedit_mode_string);
3888 	for (i = 0; LYEditorNames[i]; i++) {
3889 	    char temp[DigitsOf(i) + 3];
3890 
3891 	    sprintf(temp, "%d", i);
3892 	    PutOption(fp0, i == current_lineedit, temp, LYEditorNames[i]);
3893 	}
3894 	EndSelect(fp0);
3895     }
3896 #ifdef EXP_KEYBOARD_LAYOUT
3897     /* Keyboard layout: SELECT */
3898     PutLabel(fp0, gettext("Keyboard layout"), kblayout_string);
3899     BeginSelect(fp0, kblayout_string);
3900     for (i = 0; LYKbLayoutNames[i]; i++) {
3901 	char temp[DigitsOf(i) + 3];
3902 
3903 	sprintf(temp, "%d", i);
3904 	PutOption(fp0, i == current_layout, temp, LYKbLayoutNames[i]);
3905     }
3906     EndSelect(fp0);
3907 #endif /* EXP_KEYBOARD_LAYOUT */
3908 
3909     /*
3910      * Display and Character Set
3911      */
3912     PutHeader(fp0, gettext("Display and Character Set"));
3913     /*****************************************************************/
3914 
3915 #ifdef USE_LOCALE_CHARSET
3916     /* Use locale-based character set: ON/OFF */
3917     PutLabel(fp0, gettext("Use locale-based character set"), locale_charset_string);
3918     BeginSelect(fp0, locale_charset_string);
3919     PutOptValues(fp0, LYLocaleCharset, bool_values);
3920     EndSelect(fp0);
3921 #else
3922 #define LYLocaleCharset FALSE
3923 #endif
3924     PutLabel(fp0, gettext("Use HTML5 charset replacements"), html5_charsets_string);
3925     BeginSelect(fp0, html5_charsets_string);
3926     PutOptValues(fp0, html5_charsets, bool_values);
3927     EndSelect(fp0);
3928 
3929     /* Display Character Set: SELECT */
3930     PutLabel(fp0, gettext("Display character set"), display_char_set_string);
3931     MaybeSelect(fp0, LYLocaleCharset, display_char_set_string);
3932     for (i = 0; LYchar_set_names[i]; i++) {
3933 	char temp[DigitsOf(i) + 3];
3934 	size_t len = strlen(LYchar_set_names[i]);
3935 
3936 	if (len > cset_len)
3937 	    cset_len = len;
3938 	sprintf(temp, "%d", i);
3939 #ifdef USE_CHARSET_CHOICE
3940 	if (!charset_subsets[i].hide_display)
3941 #endif
3942 	    PutOption(fp0, i == current_char_set, temp, LYchar_set_names[i]);
3943     }
3944     EndSelect(fp0);
3945 
3946     /* Assume Character Set: SELECT */
3947     {
3948 	int curval;
3949 
3950 	curval = UCLYhndl_for_unspec;
3951 
3952 	/*
3953 	 * FIXME: If bogus value in lynx.cfg, then in old way, that is the
3954 	 * string that was displayed.  Now, user will never see that.  Good
3955 	 * or bad?  I don't know.  MRC
3956 	 */
3957 	if (curval == current_char_set) {
3958 	    /* ok, LYRawMode, so use UCAssume_MIMEcharset */
3959 	    curval = safeUCGetLYhndl_byMIME(UCAssume_MIMEcharset);
3960 	}
3961 	PutLabel(fp0, gettext("Assumed document character set"), assume_char_set_string);
3962 	BeginSelect(fp0, assume_char_set_string);
3963 	for (i = 0; i < LYNumCharsets; i++) {
3964 #ifdef USE_CHARSET_CHOICE
3965 	    if (!charset_subsets[i].hide_assumed)
3966 #endif
3967 		PutOption(fp0, i == curval,
3968 			  LYCharSet_UC[i].MIMEname,
3969 			  LYCharSet_UC[i].MIMEname);
3970 	}
3971 	EndSelect(fp0);
3972     }
3973 
3974 #ifdef USE_IDN2
3975     /* Internationalized Domain Names: SELECT */
3976     {
3977 	PutLabel(fp0, gettext("Internationalized domain names"), idna_mode_string);
3978 	BeginSelect(fp0, idna_mode_string);
3979 	for (i = 0; idna_values[i].value != 0; i++) {
3980 	    PutOption(fp0, idna_values[i].value == LYidnaMode,
3981 		      idna_values[i].HtmlName,
3982 		      idna_values[i].LongName);
3983 	}
3984 	EndSelect(fp0);
3985     }
3986 #endif
3987 
3988     /* Raw Mode: ON/OFF */
3989     if (LYHaveCJKCharacterSet) {
3990 	/*
3991 	 * Since CJK people hardly mixed with other world
3992 	 * we split the header to make it more readable:
3993 	 * "CJK mode" for CJK display charsets, and "Raw 8-bit" for others.
3994 	 */
3995 	PutLabel(fp0, gettext("CJK mode"), raw_mode_string);
3996     } else {
3997 	PutLabel(fp0, gettext("Raw 8-bit"), raw_mode_string);
3998     }
3999 
4000     BeginSelect(fp0, raw_mode_string);
4001     PutOptValues(fp0, LYRawMode, bool_values);
4002     EndSelect(fp0);
4003 
4004     /* X Display: INPUT */
4005     PutLabel(fp0, gettext("X Display"), x_display_string);
4006     PutTextInput(fp0, x_display_string, NonNull(x_display), text_len, "");
4007 
4008     /*
4009      * Document Appearance
4010      */
4011     PutHeader(fp0, gettext("Document Appearance"));
4012     /*****************************************************************/
4013 
4014     /* Show Color: SELECT */
4015 #if defined(USE_SLANG) || defined(COLOR_CURSES)
4016     SetupChosenShowColor();
4017     PutLabel(fp0, gettext("Show color"), show_color_string);
4018     if (no_option_save) {
4019 	MaybeSelect(fp0, !can_do_colors, show_color_string);
4020 	if (LYShowColor == SHOW_COLOR_NEVER) {
4021 	    LYShowColor = SHOW_COLOR_OFF;
4022 	} else if (LYShowColor == SHOW_COLOR_ALWAYS) {
4023 	    LYShowColor = SHOW_COLOR_ON;
4024 	}
4025 	PutOptValues(fp0, LYShowColor - SHOW_COLOR_OFF, bool_values);
4026     } else {
4027 	BeginSelect(fp0, show_color_string);
4028 	if (can_do_colors) {
4029 	    show_color_values[2].HtmlName = on_string;
4030 	    show_color_values[3].LongName = always_string;
4031 	} else {
4032 	    show_color_values[2].HtmlName = NULL;	/* suppress "ON" - kw */
4033 	    show_color_values[3].LongName = "Always try";
4034 	}
4035 	PutOptValues(fp0, LYChosenShowColor, show_color_values);
4036     }
4037     EndSelect(fp0);
4038 #endif /* USE_SLANG || COLOR_CURSES */
4039 
4040 #ifdef USE_COLOR_STYLE
4041     /* Color style: ON/OFF */
4042     if (HasOptValues(color_style_values)) {
4043 	PutLabel(fp0, gettext("Color style"), color_style_string);
4044 	BeginSelect(fp0, color_style_string);
4045 	PutOptValues(fp0, get_color_style_value(), color_style_values);
4046 	EndSelect(fp0);
4047     }
4048 #endif
4049 
4050 #ifdef USE_DEFAULT_COLORS
4051     /* Default colors: ON/OFF */
4052     if (has_colors()) {
4053 	PutLabel(fp0, gettext("Default colors"), default_colors_string);
4054 	BeginSelect(fp0, default_colors_string);
4055 	PutOptValues(fp0, LYuse_default_colors, bool_values);
4056 	EndSelect(fp0);
4057     }
4058 #endif
4059 
4060     /* Show cursor: ON/OFF */
4061     PutLabel(fp0, gettext("Show cursor"), show_cursor_string);
4062     BeginSelect(fp0, show_cursor_string);
4063     PutOptValues(fp0, LYShowCursor, bool_values);
4064     EndSelect(fp0);
4065 
4066     /* Underline links: ON/OFF */
4067     PutLabel(fp0, gettext("Underline links"), underline_links_string);
4068     BeginSelect(fp0, underline_links_string);
4069     PutOptValues(fp0, LYUnderlineLinks, bool_values);
4070     EndSelect(fp0);
4071 
4072 #ifdef USE_SCROLLBAR
4073     /* Show scrollbar: ON/OFF */
4074     PutLabel(fp0, gettext("Show scrollbar"), show_scrollbar_string);
4075     BeginSelect(fp0, show_scrollbar_string);
4076     PutOptValues(fp0, LYShowScrollbar, bool_values);
4077     EndSelect(fp0);
4078 #endif
4079 
4080     /* Select Popups: ON/OFF */
4081     PutLabel(fp0, gettext("Popups for select fields"), select_popups_string);
4082     BeginSelect(fp0, select_popups_string);
4083     PutOptValues(fp0, LYSelectPopups, bool_values);
4084     EndSelect(fp0);
4085 
4086     /* HTML error recovery: SELECT */
4087     PutLabel(fp0, gettext("HTML error recovery"), DTD_recovery_string);
4088     BeginSelect(fp0, DTD_recovery_string);
4089     PutOptValues(fp0, Old_DTD, DTD_type_values);
4090     EndSelect(fp0);
4091 
4092     /* Bad HTML messages: SELECT */
4093     PutLabel(fp0, gettext("Bad HTML messages"), bad_html_string);
4094     BeginSelect(fp0, bad_html_string);
4095     PutOptValues(fp0, cfg_bad_html, bad_html_values);
4096     EndSelect(fp0);
4097 
4098     /* Show Images: SELECT */
4099     PutLabel(fp0, gettext("Show images"), will_save_images());
4100     BeginSelect(fp0, images_string);
4101     PutOption(fp0, !pseudo_inline_alts && !clickable_images,
4102 	      images_ignore_all_string,
4103 	      images_ignore_all_string);
4104     PutOption(fp0, pseudo_inline_alts && !clickable_images,
4105 	      images_use_label_string,
4106 	      images_use_label_string);
4107     PutOption(fp0, clickable_images,
4108 	      images_use_links_string,
4109 	      images_use_links_string);
4110     EndSelect(fp0);
4111 
4112     /* Verbose Images: ON/OFF */
4113     PutLabel(fp0, gettext("Verbose images"), verbose_images_string);
4114     BeginSelect(fp0, verbose_images_string);
4115     PutOptValues(fp0, verbose_img, verbose_images_type_values);
4116     EndSelect(fp0);
4117 
4118     /* Collapse BR Tags: ON/OFF */
4119     PutLabel(fp0, gettext("Collapse BR tags"), collapse_br_tags_string);
4120     BeginSelect(fp0, collapse_br_tags_string);
4121     PutOptValues(fp0, LYCollapseBRs, collapse_br_tags_values);
4122     EndSelect(fp0);
4123 
4124     /* Trim blank lines: ON/OFF */
4125     PutLabel(fp0, gettext("Trim blank lines"), trim_blank_lines_string);
4126     BeginSelect(fp0, trim_blank_lines_string);
4127     PutOptValues(fp0, LYtrimBlankLines, trim_blank_lines_values);
4128     EndSelect(fp0);
4129 
4130     /*
4131      * Headers Transferred to Remote Servers
4132      */
4133     PutHeader(fp0, gettext("Headers Transferred to Remote Servers"));
4134     /*****************************************************************/
4135 
4136     /* Mail Address: INPUT */
4137     PutLabel(fp0, gettext("Personal mail address"), mail_address_string);
4138     PutTextInput(fp0, mail_address_string,
4139 		 NonNull(personal_mail_address), text_len, "");
4140 
4141 #ifndef NO_ANONYMOUS_EMAIL
4142     PutLabel(fp0, gettext("Personal name for mail"), personal_name_string);
4143     PutTextInput(fp0, personal_name_string,
4144 		 NonNull(personal_mail_name), text_len, "");
4145 #endif
4146 
4147     /* Anonymous FTP Address: INPUT */
4148 #ifndef DISABLE_FTP
4149     PutLabel(fp0, gettext("Password for anonymous ftp"), anonftp_password_string);
4150     PutTextInput(fp0, anonftp_password_string,
4151 		 NonNull(anonftp_password), text_len, "");
4152 #endif
4153 
4154     /* Preferred content type: SELECT */
4155     PutLabel(fp0, gettext("Preferred content type"), preferred_content_string);
4156     BeginSelect(fp0, preferred_content_string);
4157     PutOptValues(fp0, LYContentType, content_values);
4158     EndSelect(fp0);
4159 
4160     /* Preferred media type: SELECT */
4161     PutLabel(fp0, gettext("Preferred media type"), preferred_media_string);
4162     BeginSelect(fp0, preferred_media_string);
4163     PutOptValues(fp0, LYAcceptMedia, media_values);
4164     EndSelect(fp0);
4165 
4166     /* Preferred encoding: SELECT */
4167     PutLabel(fp0, gettext("Preferred encoding"), preferred_encoding_string);
4168     BeginSelect(fp0, preferred_encoding_string);
4169     PutOptValues(fp0, LYAcceptEncoding, encoding_values);
4170     EndSelect(fp0);
4171 
4172     /* Preferred Document Character Set: INPUT */
4173     PutLabel(fp0, gettext("Preferred document character set"), preferred_doc_char_string);
4174     PutTextInput(fp0, preferred_doc_char_string,
4175 		 NonNull(pref_charset), cset_len + 2, "");
4176 
4177     /* Preferred Document Language: INPUT */
4178     PutLabel(fp0, gettext("Preferred document language"), preferred_doc_lang_string);
4179     PutTextInput(fp0, preferred_doc_lang_string,
4180 		 NonNull(language), cset_len + 2, "");
4181 
4182     /* HTTP protocol SELECT */
4183     PutLabel(fp0, gettext("HTTP protocol"), http_protocol_string);
4184     BeginSelect(fp0, http_protocol_string);
4185     PutOptValues(fp0, HTprotocolLevel, http_protocol_values);
4186     EndSelect(fp0);
4187 
4188     /* User Agent: INPUT */
4189     if (!no_useragent) {
4190 	PutLabel(fp0, gettext("Send User-Agent header"), send_user_agent_string);
4191 	PutCheckBox(fp0, send_user_agent_string, LYSendUserAgent, "");
4192 	PutLabel(fp0, gettext("User-Agent header"), user_agent_string);
4193 	PutTextInput(fp0, user_agent_string,
4194 		     NonNull(LYUserAgent), text_len, "");
4195     }
4196 
4197     /*
4198      * Listing and Accessing Files
4199      */
4200     PutHeader(fp0, gettext("Listing and Accessing Files"));
4201     /*****************************************************************/
4202 
4203 #ifndef DISABLE_FTP
4204     /* FTP sort: SELECT */
4205     PutLabel(fp0, gettext("Use Passive FTP"), passive_ftp_string);
4206     BeginSelect(fp0, passive_ftp_string);
4207     PutOptValues(fp0, ftp_passive, bool_values);
4208     EndSelect(fp0);
4209 
4210     /* FTP sort: SELECT */
4211     PutLabel(fp0, gettext("FTP sort criteria"), ftp_sort_string);
4212     BeginSelect(fp0, ftp_sort_string);
4213     PutOptValues(fp0, HTfileSortMethod, ftp_sort_values);
4214     EndSelect(fp0);
4215 #endif /* DISABLE_FTP */
4216 
4217 #ifdef DIRED_SUPPORT
4218     /* Local Directory Sort: SELECT */
4219     PutLabel(fp0, gettext("Local directory sort criteria"), dired_list_string);
4220     BeginSelect(fp0, dired_list_string);
4221     PutOptValues(fp0, dir_list_style, dired_list_values);
4222     EndSelect(fp0);
4223 #ifdef LONG_LIST
4224     /* Local Directory Order: SELECT */
4225     PutLabel(fp0, gettext("Local directory sort order"), dired_sort_string);
4226     BeginSelect(fp0, dired_sort_string);
4227     PutOptValues(fp0, dir_list_order, dired_sort_values);
4228     EndSelect(fp0);
4229 #endif /* LONG_LIST */
4230 #endif /* DIRED_SUPPORT */
4231 
4232     /* Show dot files: ON/OFF */
4233     if (!no_dotfiles) {
4234 	PutLabel(fp0, gettext("Show dot files"), show_dotfiles_string);
4235 	BeginSelect(fp0, show_dotfiles_string);
4236 	PutOptValues(fp0, show_dotfiles, bool_values);
4237 	EndSelect(fp0);
4238     }
4239 
4240     /* Execution links: SELECT */
4241 #if defined(ENABLE_OPTS_CHANGE_EXEC) && (defined(EXEC_LINKS) || defined(EXEC_SCRIPTS))
4242     PutLabel(fp0, gettext("Execution links"), exec_links_string);
4243     BeginSelect(fp0, exec_links_string);
4244 #ifndef NEVER_ALLOW_REMOTE_EXEC
4245     PutOptValues(fp0, local_exec
4246 		 ? EXEC_ALWAYS
4247 		 : (local_exec_on_local_files
4248 		    ? EXEC_LOCAL
4249 		    : EXEC_NEVER),
4250 		 exec_links_values);
4251 #else
4252     PutOptValues(fp0, local_exec_on_local_files
4253 		 ? EXEC_LOCAL
4254 		 : EXEC_NEVER,
4255 		 exec_links_values);
4256 #endif /* !NEVER_ALLOW_REMOTE_EXEC */
4257     EndSelect(fp0);
4258 #endif /* ENABLE_OPTS_CHANGE_EXEC */
4259 
4260     PutLabel(fp0, gettext("Pause when showing message"), no_pause_string);
4261     BeginSelect(fp0, no_pause_string);
4262     PutOptValues(fp0, !no_pause, bool_values);
4263     EndSelect(fp0);
4264 
4265 #ifdef USE_READPROGRESS
4266     /* Show transfer rate: SELECT */
4267     PutLabel(fp0, gettext("Show transfer rate"), show_rate_string);
4268     BeginSelect(fp0, show_rate_string);
4269     for (i = 0; rate_values[i].LongName != 0; ++i) {
4270 	char *message = NULL;
4271 
4272 	HTSprintf0(&message,
4273 		   rate_values[i].LongName,
4274 		   HTProgressUnits(rate_values[i].value));
4275 	PutOption(fp0,
4276 		  LYTransferRate == rate_values[i].value,
4277 		  rate_values[i].HtmlName,
4278 		  message);
4279 	FREE(message);
4280     }
4281     EndSelect(fp0);
4282 #endif /* USE_READPROGRESS */
4283 
4284     /*
4285      * Special Files and Screens
4286      */
4287     PutHeader(fp0, gettext("Special Files and Screens"));
4288     /*****************************************************************/
4289 
4290     /* Multi-Bookmark Mode: SELECT */
4291     if (!LYMBMBlocked) {
4292 	PutLabel(fp0, gettext("Multi-bookmarks"), mbm_string);
4293 	BeginSelect(fp0, mbm_string);
4294 	PutOptValues(fp0, LYMultiBookmarks, mbm_values);
4295 	EndSelect(fp0);
4296     }
4297 
4298     /* Bookmarks File Menu: LINK/INPUT */
4299     if (LYMultiBookmarks) {
4300 	PutLabel(fp0, gettext("Review/edit Bookmarks files"), mbm_string);
4301 	fprintf(fp0, "<a href=\"%s\">%s</a>\n",
4302 		LYNXOPTIONS_PAGE(MBM_LINK),
4303 		LYEntifyTitle(&buffer, gettext("Goto multi-bookmark menu")));
4304     } else {
4305 	PutLabel(fp0, gettext("Bookmarks file"), single_bookmark_string);
4306 	PutTextInput(fp0, single_bookmark_string,
4307 		     NonNull(bookmark_page), text_len, "");
4308     }
4309 
4310 #ifdef USE_SESSIONS
4311     /* Auto Session: ON/OFF */
4312     PutLabel(fp0, gettext("Auto Session"), auto_session_string);
4313     BeginSelect(fp0, auto_session_string);
4314     PutOptValues(fp0, LYAutoSession, bool_values);
4315     EndSelect(fp0);
4316 
4317     /* Session File Menu: INPUT */
4318     PutLabel(fp0, gettext("Session file"), single_session_string);
4319     PutTextInput(fp0, single_session_string,
4320 		 NonNull(LYSessionFile), text_len, "");
4321 #endif
4322 
4323     /* Visited Pages: SELECT */
4324     PutLabel(fp0, gettext("Visited Pages"), visited_links_string);
4325     LYMenuVisitedLinks(fp0, disable_all);
4326 
4327     if (!no_lynxcfg_info) {
4328 	fprintf(fp0, "\n  %s<a href=\"%s\">lynx.cfg</a>.\n",
4329 		LYEntifyTitle(&buffer, gettext("View the file ")),
4330 		STR_LYNXCFG);
4331     }
4332 
4333     fprintf(fp0, "\n</pre>\n");
4334 
4335     /* Submit/Reset */
4336     if (!disable_all) {
4337 	fprintf(fp0, "<p align=center>\n");
4338 	fprintf(fp0,
4339 		"<input type=\"submit\" value=\"%s\"> - \n",
4340 		LYEntifyValue(&buffer, ACCEPT_CHANGES));
4341 	fprintf(fp0,
4342 		"<input type=\"reset\" value=\"%s\"> - \n",
4343 		LYEntifyValue(&buffer, RESET_CHANGES));
4344 	fprintf(fp0, "%s\n", LYEntifyTitle(&buffer, CANCEL_CHANGES));
4345     }
4346 
4347     /*
4348      * close HTML
4349      */
4350     fprintf(fp0, "</form>\n");
4351     EndInternalPage(fp0);
4352 
4353     FREE(buffer);
4354 
4355     LYCloseTempFP(fp0);
4356     return (NORMAL);
4357 }
4358 
4359 #endif /* !NO_OPTION_FORMS */
4360